xref: /minix3/crypto/external/bsd/netpgp/dist/src/lib/writer.c (revision ebfedea0ce5bbe81e252ddf32d732e40fb633fae)
1*ebfedea0SLionel Sambuc /*-
2*ebfedea0SLionel Sambuc  * Copyright (c) 2009 The NetBSD Foundation, Inc.
3*ebfedea0SLionel Sambuc  * All rights reserved.
4*ebfedea0SLionel Sambuc  *
5*ebfedea0SLionel Sambuc  * This code is derived from software contributed to The NetBSD Foundation
6*ebfedea0SLionel Sambuc  * by Alistair Crooks (agc@NetBSD.org)
7*ebfedea0SLionel Sambuc  *
8*ebfedea0SLionel Sambuc  * Redistribution and use in source and binary forms, with or without
9*ebfedea0SLionel Sambuc  * modification, are permitted provided that the following conditions
10*ebfedea0SLionel Sambuc  * are met:
11*ebfedea0SLionel Sambuc  * 1. Redistributions of source code must retain the above copyright
12*ebfedea0SLionel Sambuc  *    notice, this list of conditions and the following disclaimer.
13*ebfedea0SLionel Sambuc  * 2. Redistributions in binary form must reproduce the above copyright
14*ebfedea0SLionel Sambuc  *    notice, this list of conditions and the following disclaimer in the
15*ebfedea0SLionel Sambuc  *    documentation and/or other materials provided with the distribution.
16*ebfedea0SLionel Sambuc  *
17*ebfedea0SLionel Sambuc  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18*ebfedea0SLionel Sambuc  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19*ebfedea0SLionel Sambuc  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20*ebfedea0SLionel Sambuc  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21*ebfedea0SLionel Sambuc  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22*ebfedea0SLionel Sambuc  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23*ebfedea0SLionel Sambuc  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24*ebfedea0SLionel Sambuc  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25*ebfedea0SLionel Sambuc  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26*ebfedea0SLionel Sambuc  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27*ebfedea0SLionel Sambuc  * POSSIBILITY OF SUCH DAMAGE.
28*ebfedea0SLionel Sambuc  */
29*ebfedea0SLionel Sambuc /*
30*ebfedea0SLionel Sambuc  * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
31*ebfedea0SLionel Sambuc  * All rights reserved.
32*ebfedea0SLionel Sambuc  * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
33*ebfedea0SLionel Sambuc  * their moral rights under the UK Copyright Design and Patents Act 1988 to
34*ebfedea0SLionel Sambuc  * be recorded as the authors of this copyright work.
35*ebfedea0SLionel Sambuc  *
36*ebfedea0SLionel Sambuc  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
37*ebfedea0SLionel Sambuc  * use this file except in compliance with the License.
38*ebfedea0SLionel Sambuc  *
39*ebfedea0SLionel Sambuc  * You may obtain a copy of the License at
40*ebfedea0SLionel Sambuc  *     http://www.apache.org/licenses/LICENSE-2.0
41*ebfedea0SLionel Sambuc  *
42*ebfedea0SLionel Sambuc  * Unless required by applicable law or agreed to in writing, software
43*ebfedea0SLionel Sambuc  * distributed under the License is distributed on an "AS IS" BASIS,
44*ebfedea0SLionel Sambuc  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
45*ebfedea0SLionel Sambuc  *
46*ebfedea0SLionel Sambuc  * See the License for the specific language governing permissions and
47*ebfedea0SLionel Sambuc  * limitations under the License.
48*ebfedea0SLionel Sambuc  */
49*ebfedea0SLionel Sambuc 
50*ebfedea0SLionel Sambuc /** \file
51*ebfedea0SLionel Sambuc  * This file contains the base functions used by the writers.
52*ebfedea0SLionel Sambuc  */
53*ebfedea0SLionel Sambuc #include "config.h"
54*ebfedea0SLionel Sambuc 
55*ebfedea0SLionel Sambuc #ifdef HAVE_SYS_CDEFS_H
56*ebfedea0SLionel Sambuc #include <sys/cdefs.h>
57*ebfedea0SLionel Sambuc #endif
58*ebfedea0SLionel Sambuc 
59*ebfedea0SLionel Sambuc #if defined(__NetBSD__)
60*ebfedea0SLionel Sambuc __COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved.");
61*ebfedea0SLionel Sambuc __RCSID("$NetBSD: writer.c,v 1.33 2012/03/05 02:20:18 christos Exp $");
62*ebfedea0SLionel Sambuc #endif
63*ebfedea0SLionel Sambuc 
64*ebfedea0SLionel Sambuc #include <sys/types.h>
65*ebfedea0SLionel Sambuc 
66*ebfedea0SLionel Sambuc #include <stdlib.h>
67*ebfedea0SLionel Sambuc #include <string.h>
68*ebfedea0SLionel Sambuc 
69*ebfedea0SLionel Sambuc #ifdef HAVE_UNISTD_H
70*ebfedea0SLionel Sambuc #include <unistd.h>
71*ebfedea0SLionel Sambuc #endif
72*ebfedea0SLionel Sambuc 
73*ebfedea0SLionel Sambuc #ifdef HAVE_OPENSSL_CAST_H
74*ebfedea0SLionel Sambuc #include <openssl/cast.h>
75*ebfedea0SLionel Sambuc #endif
76*ebfedea0SLionel Sambuc 
77*ebfedea0SLionel Sambuc #include "create.h"
78*ebfedea0SLionel Sambuc #include "writer.h"
79*ebfedea0SLionel Sambuc #include "keyring.h"
80*ebfedea0SLionel Sambuc #include "signature.h"
81*ebfedea0SLionel Sambuc #include "packet.h"
82*ebfedea0SLionel Sambuc #include "packet-parse.h"
83*ebfedea0SLionel Sambuc #include "readerwriter.h"
84*ebfedea0SLionel Sambuc #include "memory.h"
85*ebfedea0SLionel Sambuc #include "netpgpdefs.h"
86*ebfedea0SLionel Sambuc #include "version.h"
87*ebfedea0SLionel Sambuc #include "netpgpdigest.h"
88*ebfedea0SLionel Sambuc 
89*ebfedea0SLionel Sambuc 
90*ebfedea0SLionel Sambuc /*
91*ebfedea0SLionel Sambuc  * return 1 if OK, otherwise 0
92*ebfedea0SLionel Sambuc  */
93*ebfedea0SLionel Sambuc static unsigned
base_write(pgp_output_t * out,const void * src,unsigned len)94*ebfedea0SLionel Sambuc base_write(pgp_output_t *out, const void *src, unsigned len)
95*ebfedea0SLionel Sambuc {
96*ebfedea0SLionel Sambuc 	return out->writer.writer(src, len, &out->errors, &out->writer);
97*ebfedea0SLionel Sambuc }
98*ebfedea0SLionel Sambuc 
99*ebfedea0SLionel Sambuc /**
100*ebfedea0SLionel Sambuc  * \ingroup Core_WritePackets
101*ebfedea0SLionel Sambuc  *
102*ebfedea0SLionel Sambuc  * \param src
103*ebfedea0SLionel Sambuc  * \param len
104*ebfedea0SLionel Sambuc  * \param output
105*ebfedea0SLionel Sambuc  * \return 1 if OK, otherwise 0
106*ebfedea0SLionel Sambuc  */
107*ebfedea0SLionel Sambuc 
108*ebfedea0SLionel Sambuc unsigned
pgp_write(pgp_output_t * output,const void * src,unsigned len)109*ebfedea0SLionel Sambuc pgp_write(pgp_output_t *output, const void *src, unsigned len)
110*ebfedea0SLionel Sambuc {
111*ebfedea0SLionel Sambuc 	return base_write(output, src, len);
112*ebfedea0SLionel Sambuc }
113*ebfedea0SLionel Sambuc 
114*ebfedea0SLionel Sambuc /**
115*ebfedea0SLionel Sambuc  * \ingroup Core_WritePackets
116*ebfedea0SLionel Sambuc  * \param n
117*ebfedea0SLionel Sambuc  * \param len
118*ebfedea0SLionel Sambuc  * \param output
119*ebfedea0SLionel Sambuc  * \return 1 if OK, otherwise 0
120*ebfedea0SLionel Sambuc  */
121*ebfedea0SLionel Sambuc 
122*ebfedea0SLionel Sambuc unsigned
pgp_write_scalar(pgp_output_t * output,unsigned n,unsigned len)123*ebfedea0SLionel Sambuc pgp_write_scalar(pgp_output_t *output, unsigned n, unsigned len)
124*ebfedea0SLionel Sambuc {
125*ebfedea0SLionel Sambuc 	uint8_t   c;
126*ebfedea0SLionel Sambuc 
127*ebfedea0SLionel Sambuc 	while (len-- > 0) {
128*ebfedea0SLionel Sambuc 		c = n >> (len * 8);
129*ebfedea0SLionel Sambuc 		if (!base_write(output, &c, 1)) {
130*ebfedea0SLionel Sambuc 			return 0;
131*ebfedea0SLionel Sambuc 		}
132*ebfedea0SLionel Sambuc 	}
133*ebfedea0SLionel Sambuc 	return 1;
134*ebfedea0SLionel Sambuc }
135*ebfedea0SLionel Sambuc 
136*ebfedea0SLionel Sambuc /**
137*ebfedea0SLionel Sambuc  * \ingroup Core_WritePackets
138*ebfedea0SLionel Sambuc  * \param bn
139*ebfedea0SLionel Sambuc  * \param output
140*ebfedea0SLionel Sambuc  * \return 1 if OK, otherwise 0
141*ebfedea0SLionel Sambuc  */
142*ebfedea0SLionel Sambuc 
143*ebfedea0SLionel Sambuc unsigned
pgp_write_mpi(pgp_output_t * output,const BIGNUM * bn)144*ebfedea0SLionel Sambuc pgp_write_mpi(pgp_output_t *output, const BIGNUM *bn)
145*ebfedea0SLionel Sambuc {
146*ebfedea0SLionel Sambuc 	unsigned	bits;
147*ebfedea0SLionel Sambuc 	uint8_t		buf[NETPGP_BUFSIZ];
148*ebfedea0SLionel Sambuc 
149*ebfedea0SLionel Sambuc 	bits = (unsigned)BN_num_bits(bn);
150*ebfedea0SLionel Sambuc 	if (bits > 65535) {
151*ebfedea0SLionel Sambuc 		(void) fprintf(stderr, "pgp_write_mpi: too large %u\n", bits);
152*ebfedea0SLionel Sambuc 		return 0;
153*ebfedea0SLionel Sambuc 	}
154*ebfedea0SLionel Sambuc 	BN_bn2bin(bn, buf);
155*ebfedea0SLionel Sambuc 	return pgp_write_scalar(output, bits, 2) &&
156*ebfedea0SLionel Sambuc 		pgp_write(output, buf, (bits + 7) / 8);
157*ebfedea0SLionel Sambuc }
158*ebfedea0SLionel Sambuc 
159*ebfedea0SLionel Sambuc /**
160*ebfedea0SLionel Sambuc  * \ingroup Core_WritePackets
161*ebfedea0SLionel Sambuc  * \param tag
162*ebfedea0SLionel Sambuc  * \param output
163*ebfedea0SLionel Sambuc  * \return 1 if OK, otherwise 0
164*ebfedea0SLionel Sambuc  */
165*ebfedea0SLionel Sambuc 
166*ebfedea0SLionel Sambuc unsigned
pgp_write_ptag(pgp_output_t * output,pgp_content_enum tag)167*ebfedea0SLionel Sambuc pgp_write_ptag(pgp_output_t *output, pgp_content_enum tag)
168*ebfedea0SLionel Sambuc {
169*ebfedea0SLionel Sambuc 	uint8_t   c;
170*ebfedea0SLionel Sambuc 
171*ebfedea0SLionel Sambuc 	c = tag | PGP_PTAG_ALWAYS_SET | PGP_PTAG_NEW_FORMAT;
172*ebfedea0SLionel Sambuc 	return base_write(output, &c, 1);
173*ebfedea0SLionel Sambuc }
174*ebfedea0SLionel Sambuc 
175*ebfedea0SLionel Sambuc /**
176*ebfedea0SLionel Sambuc  * \ingroup Core_WritePackets
177*ebfedea0SLionel Sambuc  * \param len
178*ebfedea0SLionel Sambuc  * \param output
179*ebfedea0SLionel Sambuc  * \return 1 if OK, otherwise 0
180*ebfedea0SLionel Sambuc  */
181*ebfedea0SLionel Sambuc 
182*ebfedea0SLionel Sambuc unsigned
pgp_write_length(pgp_output_t * output,unsigned len)183*ebfedea0SLionel Sambuc pgp_write_length(pgp_output_t *output, unsigned len)
184*ebfedea0SLionel Sambuc {
185*ebfedea0SLionel Sambuc 	uint8_t   c[2];
186*ebfedea0SLionel Sambuc 
187*ebfedea0SLionel Sambuc 	if (len < 192) {
188*ebfedea0SLionel Sambuc 		c[0] = len;
189*ebfedea0SLionel Sambuc 		return base_write(output, c, 1);
190*ebfedea0SLionel Sambuc 	}
191*ebfedea0SLionel Sambuc 	if (len < 8192 + 192) {
192*ebfedea0SLionel Sambuc 		c[0] = ((len - 192) >> 8) + 192;
193*ebfedea0SLionel Sambuc 		c[1] = (len - 192) % 256;
194*ebfedea0SLionel Sambuc 		return base_write(output, c, 2);
195*ebfedea0SLionel Sambuc 	}
196*ebfedea0SLionel Sambuc 	return pgp_write_scalar(output, 0xff, 1) &&
197*ebfedea0SLionel Sambuc 		pgp_write_scalar(output, len, 4);
198*ebfedea0SLionel Sambuc }
199*ebfedea0SLionel Sambuc 
200*ebfedea0SLionel Sambuc /*
201*ebfedea0SLionel Sambuc  * Note that we finalise from the top down, so we don't use writers below
202*ebfedea0SLionel Sambuc  * that have already been finalised
203*ebfedea0SLionel Sambuc  */
204*ebfedea0SLionel Sambuc unsigned
pgp_writer_info_finalise(pgp_error_t ** errors,pgp_writer_t * writer)205*ebfedea0SLionel Sambuc pgp_writer_info_finalise(pgp_error_t **errors, pgp_writer_t *writer)
206*ebfedea0SLionel Sambuc {
207*ebfedea0SLionel Sambuc 	unsigned   ret = 1;
208*ebfedea0SLionel Sambuc 
209*ebfedea0SLionel Sambuc 	if (writer->finaliser) {
210*ebfedea0SLionel Sambuc 		ret = writer->finaliser(errors, writer);
211*ebfedea0SLionel Sambuc 		writer->finaliser = NULL;
212*ebfedea0SLionel Sambuc 	}
213*ebfedea0SLionel Sambuc 	if (writer->next && !pgp_writer_info_finalise(errors, writer->next)) {
214*ebfedea0SLionel Sambuc 		writer->finaliser = NULL;
215*ebfedea0SLionel Sambuc 		return 0;
216*ebfedea0SLionel Sambuc 	}
217*ebfedea0SLionel Sambuc 	return ret;
218*ebfedea0SLionel Sambuc }
219*ebfedea0SLionel Sambuc 
220*ebfedea0SLionel Sambuc void
pgp_writer_info_delete(pgp_writer_t * writer)221*ebfedea0SLionel Sambuc pgp_writer_info_delete(pgp_writer_t *writer)
222*ebfedea0SLionel Sambuc {
223*ebfedea0SLionel Sambuc 	/* we should have finalised before deleting */
224*ebfedea0SLionel Sambuc 	if (writer->finaliser) {
225*ebfedea0SLionel Sambuc 		(void) fprintf(stderr, "pgp_writer_info_delete: not done\n");
226*ebfedea0SLionel Sambuc 		return;
227*ebfedea0SLionel Sambuc 	}
228*ebfedea0SLionel Sambuc 	if (writer->next) {
229*ebfedea0SLionel Sambuc 		pgp_writer_info_delete(writer->next);
230*ebfedea0SLionel Sambuc 		free(writer->next);
231*ebfedea0SLionel Sambuc 		writer->next = NULL;
232*ebfedea0SLionel Sambuc 	}
233*ebfedea0SLionel Sambuc 	if (writer->destroyer) {
234*ebfedea0SLionel Sambuc 		writer->destroyer(writer);
235*ebfedea0SLionel Sambuc 		writer->destroyer = NULL;
236*ebfedea0SLionel Sambuc 	}
237*ebfedea0SLionel Sambuc 	writer->writer = NULL;
238*ebfedea0SLionel Sambuc }
239*ebfedea0SLionel Sambuc 
240*ebfedea0SLionel Sambuc /**
241*ebfedea0SLionel Sambuc  * \ingroup Core_Writers
242*ebfedea0SLionel Sambuc  *
243*ebfedea0SLionel Sambuc  * Set a writer in output. There should not be another writer set.
244*ebfedea0SLionel Sambuc  *
245*ebfedea0SLionel Sambuc  * \param output The output structure
246*ebfedea0SLionel Sambuc  * \param writer
247*ebfedea0SLionel Sambuc  * \param finaliser
248*ebfedea0SLionel Sambuc  * \param destroyer
249*ebfedea0SLionel Sambuc  * \param arg The argument for the writer and destroyer
250*ebfedea0SLionel Sambuc  */
251*ebfedea0SLionel Sambuc void
pgp_writer_set(pgp_output_t * output,pgp_writer_func_t * writer,pgp_writer_finaliser_t * finaliser,pgp_writer_destroyer_t * destroyer,void * arg)252*ebfedea0SLionel Sambuc pgp_writer_set(pgp_output_t *output,
253*ebfedea0SLionel Sambuc 	       pgp_writer_func_t *writer,
254*ebfedea0SLionel Sambuc 	       pgp_writer_finaliser_t *finaliser,
255*ebfedea0SLionel Sambuc 	       pgp_writer_destroyer_t *destroyer,
256*ebfedea0SLionel Sambuc 	       void *arg)
257*ebfedea0SLionel Sambuc {
258*ebfedea0SLionel Sambuc 	if (output->writer.writer) {
259*ebfedea0SLionel Sambuc 		(void) fprintf(stderr, "pgp_writer_set: already set\n");
260*ebfedea0SLionel Sambuc 	} else {
261*ebfedea0SLionel Sambuc 		output->writer.writer = writer;
262*ebfedea0SLionel Sambuc 		output->writer.finaliser = finaliser;
263*ebfedea0SLionel Sambuc 		output->writer.destroyer = destroyer;
264*ebfedea0SLionel Sambuc 		output->writer.arg = arg;
265*ebfedea0SLionel Sambuc 	}
266*ebfedea0SLionel Sambuc }
267*ebfedea0SLionel Sambuc 
268*ebfedea0SLionel Sambuc /**
269*ebfedea0SLionel Sambuc  * \ingroup Core_Writers
270*ebfedea0SLionel Sambuc  *
271*ebfedea0SLionel Sambuc  * Push a writer in output. There must already be another writer set.
272*ebfedea0SLionel Sambuc  *
273*ebfedea0SLionel Sambuc  * \param output The output structure
274*ebfedea0SLionel Sambuc  * \param writer
275*ebfedea0SLionel Sambuc  * \param finaliser
276*ebfedea0SLionel Sambuc  * \param destroyer
277*ebfedea0SLionel Sambuc  * \param arg The argument for the writer and destroyer
278*ebfedea0SLionel Sambuc  */
279*ebfedea0SLionel Sambuc void
pgp_writer_push(pgp_output_t * output,pgp_writer_func_t * writer,pgp_writer_finaliser_t * finaliser,pgp_writer_destroyer_t * destroyer,void * arg)280*ebfedea0SLionel Sambuc pgp_writer_push(pgp_output_t *output,
281*ebfedea0SLionel Sambuc 		pgp_writer_func_t *writer,
282*ebfedea0SLionel Sambuc 		pgp_writer_finaliser_t *finaliser,
283*ebfedea0SLionel Sambuc 		pgp_writer_destroyer_t *destroyer,
284*ebfedea0SLionel Sambuc 		void *arg)
285*ebfedea0SLionel Sambuc {
286*ebfedea0SLionel Sambuc 	pgp_writer_t *copy;
287*ebfedea0SLionel Sambuc 
288*ebfedea0SLionel Sambuc 	if ((copy = calloc(1, sizeof(*copy))) == NULL) {
289*ebfedea0SLionel Sambuc 		(void) fprintf(stderr, "pgp_writer_push: bad alloc\n");
290*ebfedea0SLionel Sambuc 	} else if (output->writer.writer == NULL) {
291*ebfedea0SLionel Sambuc 		(void) fprintf(stderr, "pgp_writer_push: no orig writer\n");
292*ebfedea0SLionel Sambuc 	} else {
293*ebfedea0SLionel Sambuc 		*copy = output->writer;
294*ebfedea0SLionel Sambuc 		output->writer.next = copy;
295*ebfedea0SLionel Sambuc 
296*ebfedea0SLionel Sambuc 		output->writer.writer = writer;
297*ebfedea0SLionel Sambuc 		output->writer.finaliser = finaliser;
298*ebfedea0SLionel Sambuc 		output->writer.destroyer = destroyer;
299*ebfedea0SLionel Sambuc 		output->writer.arg = arg;
300*ebfedea0SLionel Sambuc 	}
301*ebfedea0SLionel Sambuc }
302*ebfedea0SLionel Sambuc 
303*ebfedea0SLionel Sambuc void
pgp_writer_pop(pgp_output_t * output)304*ebfedea0SLionel Sambuc pgp_writer_pop(pgp_output_t *output)
305*ebfedea0SLionel Sambuc {
306*ebfedea0SLionel Sambuc 	pgp_writer_t *next;
307*ebfedea0SLionel Sambuc 
308*ebfedea0SLionel Sambuc 	/* Make sure the finaliser has been called. */
309*ebfedea0SLionel Sambuc 	if (output->writer.finaliser) {
310*ebfedea0SLionel Sambuc 		(void) fprintf(stderr,
311*ebfedea0SLionel Sambuc 			"pgp_writer_pop: finaliser not called\n");
312*ebfedea0SLionel Sambuc 	} else if (output->writer.next == NULL) {
313*ebfedea0SLionel Sambuc 		(void) fprintf(stderr,
314*ebfedea0SLionel Sambuc 			"pgp_writer_pop: not a stacked writer\n");
315*ebfedea0SLionel Sambuc 	} else {
316*ebfedea0SLionel Sambuc 		if (output->writer.destroyer) {
317*ebfedea0SLionel Sambuc 			output->writer.destroyer(&output->writer);
318*ebfedea0SLionel Sambuc 		}
319*ebfedea0SLionel Sambuc 		next = output->writer.next;
320*ebfedea0SLionel Sambuc 		output->writer = *next;
321*ebfedea0SLionel Sambuc 		free(next);
322*ebfedea0SLionel Sambuc 	}
323*ebfedea0SLionel Sambuc }
324*ebfedea0SLionel Sambuc 
325*ebfedea0SLionel Sambuc /**
326*ebfedea0SLionel Sambuc  * \ingroup Core_Writers
327*ebfedea0SLionel Sambuc  *
328*ebfedea0SLionel Sambuc  * Close the writer currently set in output.
329*ebfedea0SLionel Sambuc  *
330*ebfedea0SLionel Sambuc  * \param output The output structure
331*ebfedea0SLionel Sambuc  */
332*ebfedea0SLionel Sambuc unsigned
pgp_writer_close(pgp_output_t * output)333*ebfedea0SLionel Sambuc pgp_writer_close(pgp_output_t *output)
334*ebfedea0SLionel Sambuc {
335*ebfedea0SLionel Sambuc 	unsigned   ret;
336*ebfedea0SLionel Sambuc 
337*ebfedea0SLionel Sambuc 	ret = pgp_writer_info_finalise(&output->errors, &output->writer);
338*ebfedea0SLionel Sambuc 	pgp_writer_info_delete(&output->writer);
339*ebfedea0SLionel Sambuc 	return ret;
340*ebfedea0SLionel Sambuc }
341*ebfedea0SLionel Sambuc 
342*ebfedea0SLionel Sambuc /**
343*ebfedea0SLionel Sambuc  * \ingroup Core_Writers
344*ebfedea0SLionel Sambuc  *
345*ebfedea0SLionel Sambuc  * Get the arg supplied to pgp_createinfo_set_writer().
346*ebfedea0SLionel Sambuc  *
347*ebfedea0SLionel Sambuc  * \param writer The writer_info structure
348*ebfedea0SLionel Sambuc  * \return The arg
349*ebfedea0SLionel Sambuc  */
350*ebfedea0SLionel Sambuc void           *
pgp_writer_get_arg(pgp_writer_t * writer)351*ebfedea0SLionel Sambuc pgp_writer_get_arg(pgp_writer_t *writer)
352*ebfedea0SLionel Sambuc {
353*ebfedea0SLionel Sambuc 	return writer->arg;
354*ebfedea0SLionel Sambuc }
355*ebfedea0SLionel Sambuc 
356*ebfedea0SLionel Sambuc /**
357*ebfedea0SLionel Sambuc  * \ingroup Core_Writers
358*ebfedea0SLionel Sambuc  *
359*ebfedea0SLionel Sambuc  * Write to the next writer down in the stack.
360*ebfedea0SLionel Sambuc  *
361*ebfedea0SLionel Sambuc  * \param src The data to write.
362*ebfedea0SLionel Sambuc  * \param len The length of src.
363*ebfedea0SLionel Sambuc  * \param errors A place to store errors.
364*ebfedea0SLionel Sambuc  * \param writer The writer_info structure.
365*ebfedea0SLionel Sambuc  * \return Success - if 0, then errors should contain the error.
366*ebfedea0SLionel Sambuc  */
367*ebfedea0SLionel Sambuc static unsigned
stacked_write(pgp_writer_t * writer,const void * src,unsigned len,pgp_error_t ** errors)368*ebfedea0SLionel Sambuc stacked_write(pgp_writer_t *writer, const void *src, unsigned len,
369*ebfedea0SLionel Sambuc 		  pgp_error_t ** errors)
370*ebfedea0SLionel Sambuc {
371*ebfedea0SLionel Sambuc 	return writer->next->writer(src, len, errors, writer->next);
372*ebfedea0SLionel Sambuc }
373*ebfedea0SLionel Sambuc 
374*ebfedea0SLionel Sambuc /**
375*ebfedea0SLionel Sambuc  * \ingroup Core_Writers
376*ebfedea0SLionel Sambuc  *
377*ebfedea0SLionel Sambuc  * Free the arg. Many writers just have a calloc()ed lump of storage, this
378*ebfedea0SLionel Sambuc  * function releases it.
379*ebfedea0SLionel Sambuc  *
380*ebfedea0SLionel Sambuc  * \param writer the info structure.
381*ebfedea0SLionel Sambuc  */
382*ebfedea0SLionel Sambuc static void
generic_destroyer(pgp_writer_t * writer)383*ebfedea0SLionel Sambuc generic_destroyer(pgp_writer_t *writer)
384*ebfedea0SLionel Sambuc {
385*ebfedea0SLionel Sambuc 	free(pgp_writer_get_arg(writer));
386*ebfedea0SLionel Sambuc }
387*ebfedea0SLionel Sambuc 
388*ebfedea0SLionel Sambuc /**
389*ebfedea0SLionel Sambuc  * \ingroup Core_Writers
390*ebfedea0SLionel Sambuc  *
391*ebfedea0SLionel Sambuc  * A writer that just writes to the next one down. Useful for when you
392*ebfedea0SLionel Sambuc  * want to insert just a finaliser into the stack.
393*ebfedea0SLionel Sambuc  */
394*ebfedea0SLionel Sambuc unsigned
pgp_writer_passthrough(const uint8_t * src,unsigned len,pgp_error_t ** errors,pgp_writer_t * writer)395*ebfedea0SLionel Sambuc pgp_writer_passthrough(const uint8_t *src,
396*ebfedea0SLionel Sambuc 		       unsigned len,
397*ebfedea0SLionel Sambuc 		       pgp_error_t **errors,
398*ebfedea0SLionel Sambuc 		       pgp_writer_t *writer)
399*ebfedea0SLionel Sambuc {
400*ebfedea0SLionel Sambuc 	return stacked_write(writer, src, len, errors);
401*ebfedea0SLionel Sambuc }
402*ebfedea0SLionel Sambuc 
403*ebfedea0SLionel Sambuc /**************************************************************************/
404*ebfedea0SLionel Sambuc 
405*ebfedea0SLionel Sambuc /**
406*ebfedea0SLionel Sambuc  * \struct dashesc_t
407*ebfedea0SLionel Sambuc  */
408*ebfedea0SLionel Sambuc typedef struct {
409*ebfedea0SLionel Sambuc 	unsigned   		 seen_nl:1;
410*ebfedea0SLionel Sambuc 	unsigned		 seen_cr:1;
411*ebfedea0SLionel Sambuc 	pgp_create_sig_t	*sig;
412*ebfedea0SLionel Sambuc 	pgp_memory_t		*trailing;
413*ebfedea0SLionel Sambuc } dashesc_t;
414*ebfedea0SLionel Sambuc 
415*ebfedea0SLionel Sambuc static unsigned
dash_esc_writer(const uint8_t * src,unsigned len,pgp_error_t ** errors,pgp_writer_t * writer)416*ebfedea0SLionel Sambuc dash_esc_writer(const uint8_t *src,
417*ebfedea0SLionel Sambuc 		    unsigned len,
418*ebfedea0SLionel Sambuc 		    pgp_error_t **errors,
419*ebfedea0SLionel Sambuc 		    pgp_writer_t *writer)
420*ebfedea0SLionel Sambuc {
421*ebfedea0SLionel Sambuc 	dashesc_t	*dash = pgp_writer_get_arg(writer);
422*ebfedea0SLionel Sambuc 	unsigned        n;
423*ebfedea0SLionel Sambuc 
424*ebfedea0SLionel Sambuc 	if (pgp_get_debug_level(__FILE__)) {
425*ebfedea0SLionel Sambuc 		unsigned    i = 0;
426*ebfedea0SLionel Sambuc 
427*ebfedea0SLionel Sambuc 		(void) fprintf(stderr, "dash_esc_writer writing %u:\n", len);
428*ebfedea0SLionel Sambuc 		for (i = 0; i < len; i++) {
429*ebfedea0SLionel Sambuc 			fprintf(stderr, "0x%02x ", src[i]);
430*ebfedea0SLionel Sambuc 			if (((i + 1) % 16) == 0) {
431*ebfedea0SLionel Sambuc 				(void) fprintf(stderr, "\n");
432*ebfedea0SLionel Sambuc 			} else if (((i + 1) % 8) == 0) {
433*ebfedea0SLionel Sambuc 				(void) fprintf(stderr, "  ");
434*ebfedea0SLionel Sambuc 			}
435*ebfedea0SLionel Sambuc 		}
436*ebfedea0SLionel Sambuc 		(void) fprintf(stderr, "\n");
437*ebfedea0SLionel Sambuc 	}
438*ebfedea0SLionel Sambuc 	/* XXX: make this efficient */
439*ebfedea0SLionel Sambuc 	for (n = 0; n < len; ++n) {
440*ebfedea0SLionel Sambuc 		unsigned        l;
441*ebfedea0SLionel Sambuc 
442*ebfedea0SLionel Sambuc 		if (dash->seen_nl) {
443*ebfedea0SLionel Sambuc 			if (src[n] == '-' &&
444*ebfedea0SLionel Sambuc 			    !stacked_write(writer, "- ", 2, errors)) {
445*ebfedea0SLionel Sambuc 				return 0;
446*ebfedea0SLionel Sambuc 			}
447*ebfedea0SLionel Sambuc 			dash->seen_nl = 0;
448*ebfedea0SLionel Sambuc 		}
449*ebfedea0SLionel Sambuc 		dash->seen_nl = src[n] == '\n';
450*ebfedea0SLionel Sambuc 
451*ebfedea0SLionel Sambuc 		if (dash->seen_nl && !dash->seen_cr) {
452*ebfedea0SLionel Sambuc 			if (!stacked_write(writer, "\r", 1, errors)) {
453*ebfedea0SLionel Sambuc 				return 0;
454*ebfedea0SLionel Sambuc 			}
455*ebfedea0SLionel Sambuc 			pgp_sig_add_data(dash->sig, "\r", 1);
456*ebfedea0SLionel Sambuc 		}
457*ebfedea0SLionel Sambuc 		dash->seen_cr = src[n] == '\r';
458*ebfedea0SLionel Sambuc 
459*ebfedea0SLionel Sambuc 		if (!stacked_write(writer, &src[n], 1, errors)) {
460*ebfedea0SLionel Sambuc 			return 0;
461*ebfedea0SLionel Sambuc 		}
462*ebfedea0SLionel Sambuc 
463*ebfedea0SLionel Sambuc 		/* trailing whitespace isn't included in the signature */
464*ebfedea0SLionel Sambuc 		if (src[n] == ' ' || src[n] == '\t') {
465*ebfedea0SLionel Sambuc 			pgp_memory_add(dash->trailing, &src[n], 1);
466*ebfedea0SLionel Sambuc 		} else {
467*ebfedea0SLionel Sambuc 			if ((l = (unsigned)pgp_mem_len(dash->trailing)) != 0) {
468*ebfedea0SLionel Sambuc 				if (!dash->seen_nl && !dash->seen_cr) {
469*ebfedea0SLionel Sambuc 					pgp_sig_add_data(dash->sig,
470*ebfedea0SLionel Sambuc 					pgp_mem_data(dash->trailing), l);
471*ebfedea0SLionel Sambuc 				}
472*ebfedea0SLionel Sambuc 				pgp_memory_clear(dash->trailing);
473*ebfedea0SLionel Sambuc 			}
474*ebfedea0SLionel Sambuc 			pgp_sig_add_data(dash->sig, &src[n], 1);
475*ebfedea0SLionel Sambuc 		}
476*ebfedea0SLionel Sambuc 	}
477*ebfedea0SLionel Sambuc 	return 1;
478*ebfedea0SLionel Sambuc }
479*ebfedea0SLionel Sambuc 
480*ebfedea0SLionel Sambuc /**
481*ebfedea0SLionel Sambuc  * \param writer
482*ebfedea0SLionel Sambuc  */
483*ebfedea0SLionel Sambuc static void
dash_escaped_destroyer(pgp_writer_t * writer)484*ebfedea0SLionel Sambuc dash_escaped_destroyer(pgp_writer_t *writer)
485*ebfedea0SLionel Sambuc {
486*ebfedea0SLionel Sambuc 	dashesc_t	*dash;
487*ebfedea0SLionel Sambuc 
488*ebfedea0SLionel Sambuc 	dash = pgp_writer_get_arg(writer);
489*ebfedea0SLionel Sambuc 	pgp_memory_free(dash->trailing);
490*ebfedea0SLionel Sambuc 	free(dash);
491*ebfedea0SLionel Sambuc }
492*ebfedea0SLionel Sambuc 
493*ebfedea0SLionel Sambuc /**
494*ebfedea0SLionel Sambuc  * \ingroup Core_WritersNext
495*ebfedea0SLionel Sambuc  * \brief Push Clearsigned Writer onto stack
496*ebfedea0SLionel Sambuc  * \param output
497*ebfedea0SLionel Sambuc  * \param sig
498*ebfedea0SLionel Sambuc  */
499*ebfedea0SLionel Sambuc unsigned
pgp_writer_push_clearsigned(pgp_output_t * output,pgp_create_sig_t * sig)500*ebfedea0SLionel Sambuc pgp_writer_push_clearsigned(pgp_output_t *output, pgp_create_sig_t *sig)
501*ebfedea0SLionel Sambuc {
502*ebfedea0SLionel Sambuc 	static const char     header[] =
503*ebfedea0SLionel Sambuc 		"-----BEGIN PGP SIGNED MESSAGE-----\r\nHash: ";
504*ebfedea0SLionel Sambuc 	const char     *hash;
505*ebfedea0SLionel Sambuc 	dashesc_t      *dash;
506*ebfedea0SLionel Sambuc 	unsigned	ret;
507*ebfedea0SLionel Sambuc 
508*ebfedea0SLionel Sambuc 	hash = pgp_text_from_hash(pgp_sig_get_hash(sig));
509*ebfedea0SLionel Sambuc 	if ((dash = calloc(1, sizeof(*dash))) == NULL) {
510*ebfedea0SLionel Sambuc 		PGP_ERROR_1(&output->errors, PGP_E_W, "%s", "Bad alloc");
511*ebfedea0SLionel Sambuc 		return 0;
512*ebfedea0SLionel Sambuc 	}
513*ebfedea0SLionel Sambuc 	ret = (pgp_write(output, header, (unsigned)(sizeof(header) - 1)) &&
514*ebfedea0SLionel Sambuc 		pgp_write(output, hash, (unsigned)strlen(hash)) &&
515*ebfedea0SLionel Sambuc 		pgp_write(output, "\r\n\r\n", 4));
516*ebfedea0SLionel Sambuc 
517*ebfedea0SLionel Sambuc 	if (ret == 0) {
518*ebfedea0SLionel Sambuc 		PGP_ERROR_1(&output->errors, PGP_E_W, "%s",
519*ebfedea0SLionel Sambuc 			"Error pushing clearsigned header");
520*ebfedea0SLionel Sambuc 		free(dash);
521*ebfedea0SLionel Sambuc 		return ret;
522*ebfedea0SLionel Sambuc 	}
523*ebfedea0SLionel Sambuc 	dash->seen_nl = 1;
524*ebfedea0SLionel Sambuc 	dash->sig = sig;
525*ebfedea0SLionel Sambuc 	dash->trailing = pgp_memory_new();
526*ebfedea0SLionel Sambuc 	pgp_writer_push(output, dash_esc_writer, NULL,
527*ebfedea0SLionel Sambuc 			dash_escaped_destroyer, dash);
528*ebfedea0SLionel Sambuc 	return ret;
529*ebfedea0SLionel Sambuc }
530*ebfedea0SLionel Sambuc 
531*ebfedea0SLionel Sambuc 
532*ebfedea0SLionel Sambuc /**
533*ebfedea0SLionel Sambuc  * \struct base64_t
534*ebfedea0SLionel Sambuc  */
535*ebfedea0SLionel Sambuc typedef struct {
536*ebfedea0SLionel Sambuc 	unsigned	pos;
537*ebfedea0SLionel Sambuc 	uint8_t		t;
538*ebfedea0SLionel Sambuc 	unsigned	checksum;
539*ebfedea0SLionel Sambuc } base64_t;
540*ebfedea0SLionel Sambuc 
541*ebfedea0SLionel Sambuc static const char     b64map[] =
542*ebfedea0SLionel Sambuc 	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
543*ebfedea0SLionel Sambuc 
544*ebfedea0SLionel Sambuc static unsigned
base64_writer(const uint8_t * src,unsigned len,pgp_error_t ** errors,pgp_writer_t * writer)545*ebfedea0SLionel Sambuc base64_writer(const uint8_t *src,
546*ebfedea0SLionel Sambuc 	      unsigned len,
547*ebfedea0SLionel Sambuc 	      pgp_error_t **errors,
548*ebfedea0SLionel Sambuc 	      pgp_writer_t *writer)
549*ebfedea0SLionel Sambuc {
550*ebfedea0SLionel Sambuc 	base64_t	*base64;
551*ebfedea0SLionel Sambuc 	unsigned         n;
552*ebfedea0SLionel Sambuc 
553*ebfedea0SLionel Sambuc 	base64 = pgp_writer_get_arg(writer);
554*ebfedea0SLionel Sambuc 	for (n = 0; n < len;) {
555*ebfedea0SLionel Sambuc 		base64->checksum = pgp_crc24(base64->checksum, src[n]);
556*ebfedea0SLionel Sambuc 		if (base64->pos == 0) {
557*ebfedea0SLionel Sambuc 			/* XXXXXX00 00000000 00000000 */
558*ebfedea0SLionel Sambuc 			if (!stacked_write(writer,
559*ebfedea0SLionel Sambuc 					&b64map[(unsigned)src[n] >> 2],
560*ebfedea0SLionel Sambuc 					1, errors)) {
561*ebfedea0SLionel Sambuc 				return 0;
562*ebfedea0SLionel Sambuc 			}
563*ebfedea0SLionel Sambuc 
564*ebfedea0SLionel Sambuc 			/* 000000XX xxxx0000 00000000 */
565*ebfedea0SLionel Sambuc 			base64->t = (src[n++] & 3) << 4;
566*ebfedea0SLionel Sambuc 			base64->pos = 1;
567*ebfedea0SLionel Sambuc 		} else if (base64->pos == 1) {
568*ebfedea0SLionel Sambuc 			/* 000000xx XXXX0000 00000000 */
569*ebfedea0SLionel Sambuc 			base64->t += (unsigned)src[n] >> 4;
570*ebfedea0SLionel Sambuc 			if (!stacked_write(writer, &b64map[base64->t], 1,
571*ebfedea0SLionel Sambuc 					errors)) {
572*ebfedea0SLionel Sambuc 				return 0;
573*ebfedea0SLionel Sambuc 			}
574*ebfedea0SLionel Sambuc 
575*ebfedea0SLionel Sambuc 			/* 00000000 0000XXXX xx000000 */
576*ebfedea0SLionel Sambuc 			base64->t = (src[n++] & 0xf) << 2;
577*ebfedea0SLionel Sambuc 			base64->pos = 2;
578*ebfedea0SLionel Sambuc 		} else if (base64->pos == 2) {
579*ebfedea0SLionel Sambuc 			/* 00000000 0000xxxx XX000000 */
580*ebfedea0SLionel Sambuc 			base64->t += (unsigned)src[n] >> 6;
581*ebfedea0SLionel Sambuc 			if (!stacked_write(writer, &b64map[base64->t], 1,
582*ebfedea0SLionel Sambuc 					errors)) {
583*ebfedea0SLionel Sambuc 				return 0;
584*ebfedea0SLionel Sambuc 			}
585*ebfedea0SLionel Sambuc 
586*ebfedea0SLionel Sambuc 			/* 00000000 00000000 00XXXXXX */
587*ebfedea0SLionel Sambuc 			if (!stacked_write(writer,
588*ebfedea0SLionel Sambuc 					&b64map[src[n++] & 0x3f], 1, errors)) {
589*ebfedea0SLionel Sambuc 				return 0;
590*ebfedea0SLionel Sambuc 			}
591*ebfedea0SLionel Sambuc 
592*ebfedea0SLionel Sambuc 			base64->pos = 0;
593*ebfedea0SLionel Sambuc 		}
594*ebfedea0SLionel Sambuc 	}
595*ebfedea0SLionel Sambuc 
596*ebfedea0SLionel Sambuc 	return 1;
597*ebfedea0SLionel Sambuc }
598*ebfedea0SLionel Sambuc 
599*ebfedea0SLionel Sambuc static unsigned
sig_finaliser(pgp_error_t ** errors,pgp_writer_t * writer)600*ebfedea0SLionel Sambuc sig_finaliser(pgp_error_t **errors, pgp_writer_t *writer)
601*ebfedea0SLionel Sambuc {
602*ebfedea0SLionel Sambuc 	static const char	trail[] = "\r\n-----END PGP SIGNATURE-----\r\n";
603*ebfedea0SLionel Sambuc 	base64_t		*base64;
604*ebfedea0SLionel Sambuc 	uint8_t			c[3];
605*ebfedea0SLionel Sambuc 
606*ebfedea0SLionel Sambuc 	base64 = pgp_writer_get_arg(writer);
607*ebfedea0SLionel Sambuc 	if (base64->pos) {
608*ebfedea0SLionel Sambuc 		if (!stacked_write(writer, &b64map[base64->t], 1, errors)) {
609*ebfedea0SLionel Sambuc 			return 0;
610*ebfedea0SLionel Sambuc 		}
611*ebfedea0SLionel Sambuc 		if (base64->pos == 1 &&
612*ebfedea0SLionel Sambuc 		    !stacked_write(writer, "==", 2, errors)) {
613*ebfedea0SLionel Sambuc 			return 0;
614*ebfedea0SLionel Sambuc 		}
615*ebfedea0SLionel Sambuc 		if (base64->pos == 2 &&
616*ebfedea0SLionel Sambuc 		    !stacked_write(writer, "=", 1, errors)) {
617*ebfedea0SLionel Sambuc 			return 0;
618*ebfedea0SLionel Sambuc 		}
619*ebfedea0SLionel Sambuc 	}
620*ebfedea0SLionel Sambuc 	/* Ready for the checksum */
621*ebfedea0SLionel Sambuc 	if (!stacked_write(writer, "\r\n=", 3, errors)) {
622*ebfedea0SLionel Sambuc 		return 0;
623*ebfedea0SLionel Sambuc 	}
624*ebfedea0SLionel Sambuc 
625*ebfedea0SLionel Sambuc 	base64->pos = 0;		/* get ready to write the checksum */
626*ebfedea0SLionel Sambuc 
627*ebfedea0SLionel Sambuc 	c[0] = base64->checksum >> 16;
628*ebfedea0SLionel Sambuc 	c[1] = base64->checksum >> 8;
629*ebfedea0SLionel Sambuc 	c[2] = base64->checksum;
630*ebfedea0SLionel Sambuc 	/* push the checksum through our own writer */
631*ebfedea0SLionel Sambuc 	if (!base64_writer(c, 3, errors, writer)) {
632*ebfedea0SLionel Sambuc 		return 0;
633*ebfedea0SLionel Sambuc 	}
634*ebfedea0SLionel Sambuc 
635*ebfedea0SLionel Sambuc 	return stacked_write(writer, trail, (unsigned)(sizeof(trail) - 1), errors);
636*ebfedea0SLionel Sambuc }
637*ebfedea0SLionel Sambuc 
638*ebfedea0SLionel Sambuc /**
639*ebfedea0SLionel Sambuc  * \struct linebreak_t
640*ebfedea0SLionel Sambuc  */
641*ebfedea0SLionel Sambuc typedef struct {
642*ebfedea0SLionel Sambuc 	unsigned        pos;
643*ebfedea0SLionel Sambuc } linebreak_t;
644*ebfedea0SLionel Sambuc 
645*ebfedea0SLionel Sambuc #define BREAKPOS	76
646*ebfedea0SLionel Sambuc 
647*ebfedea0SLionel Sambuc static unsigned
linebreak_writer(const uint8_t * src,unsigned len,pgp_error_t ** errors,pgp_writer_t * writer)648*ebfedea0SLionel Sambuc linebreak_writer(const uint8_t *src,
649*ebfedea0SLionel Sambuc 		 unsigned len,
650*ebfedea0SLionel Sambuc 		 pgp_error_t **errors,
651*ebfedea0SLionel Sambuc 		 pgp_writer_t *writer)
652*ebfedea0SLionel Sambuc {
653*ebfedea0SLionel Sambuc 	linebreak_t	*linebreak;
654*ebfedea0SLionel Sambuc 	unsigned         n;
655*ebfedea0SLionel Sambuc 
656*ebfedea0SLionel Sambuc 	linebreak = pgp_writer_get_arg(writer);
657*ebfedea0SLionel Sambuc 	for (n = 0; n < len; ++n, ++linebreak->pos) {
658*ebfedea0SLionel Sambuc 		if (src[n] == '\r' || src[n] == '\n') {
659*ebfedea0SLionel Sambuc 			linebreak->pos = 0;
660*ebfedea0SLionel Sambuc 		}
661*ebfedea0SLionel Sambuc 		if (linebreak->pos == BREAKPOS) {
662*ebfedea0SLionel Sambuc 			if (!stacked_write(writer, "\r\n", 2, errors)) {
663*ebfedea0SLionel Sambuc 				return 0;
664*ebfedea0SLionel Sambuc 			}
665*ebfedea0SLionel Sambuc 			linebreak->pos = 0;
666*ebfedea0SLionel Sambuc 		}
667*ebfedea0SLionel Sambuc 		if (!stacked_write(writer, &src[n], 1, errors)) {
668*ebfedea0SLionel Sambuc 			return 0;
669*ebfedea0SLionel Sambuc 		}
670*ebfedea0SLionel Sambuc 	}
671*ebfedea0SLionel Sambuc 
672*ebfedea0SLionel Sambuc 	return 1;
673*ebfedea0SLionel Sambuc }
674*ebfedea0SLionel Sambuc 
675*ebfedea0SLionel Sambuc /**
676*ebfedea0SLionel Sambuc  * \ingroup Core_WritersNext
677*ebfedea0SLionel Sambuc  * \brief Push armoured signature on stack
678*ebfedea0SLionel Sambuc  * \param output
679*ebfedea0SLionel Sambuc  */
680*ebfedea0SLionel Sambuc unsigned
pgp_writer_use_armored_sig(pgp_output_t * output)681*ebfedea0SLionel Sambuc pgp_writer_use_armored_sig(pgp_output_t *output)
682*ebfedea0SLionel Sambuc {
683*ebfedea0SLionel Sambuc 	static const char     header[] =
684*ebfedea0SLionel Sambuc 			"\r\n-----BEGIN PGP SIGNATURE-----\r\nVersion: "
685*ebfedea0SLionel Sambuc 			NETPGP_VERSION_STRING
686*ebfedea0SLionel Sambuc 			"\r\n\r\n";
687*ebfedea0SLionel Sambuc 	linebreak_t	*linebreak;
688*ebfedea0SLionel Sambuc 	base64_t   	*base64;
689*ebfedea0SLionel Sambuc 
690*ebfedea0SLionel Sambuc 	pgp_writer_pop(output);
691*ebfedea0SLionel Sambuc 	if (pgp_write(output, header, (unsigned)(sizeof(header) - 1)) == 0) {
692*ebfedea0SLionel Sambuc 		PGP_ERROR_1(&output->errors, PGP_E_W, "%s",
693*ebfedea0SLionel Sambuc 			"Error switching to armoured signature");
694*ebfedea0SLionel Sambuc 		return 0;
695*ebfedea0SLionel Sambuc 	}
696*ebfedea0SLionel Sambuc 	if ((linebreak = calloc(1, sizeof(*linebreak))) == NULL) {
697*ebfedea0SLionel Sambuc 		PGP_ERROR_1(&output->errors, PGP_E_W, "%s",
698*ebfedea0SLionel Sambuc 			"pgp_writer_use_armored_sig: Bad alloc");
699*ebfedea0SLionel Sambuc 		return 0;
700*ebfedea0SLionel Sambuc 	}
701*ebfedea0SLionel Sambuc 	pgp_writer_push(output, linebreak_writer, NULL,
702*ebfedea0SLionel Sambuc 			generic_destroyer,
703*ebfedea0SLionel Sambuc 			linebreak);
704*ebfedea0SLionel Sambuc 	base64 = calloc(1, sizeof(*base64));
705*ebfedea0SLionel Sambuc 	if (!base64) {
706*ebfedea0SLionel Sambuc 		PGP_MEMORY_ERROR(&output->errors);
707*ebfedea0SLionel Sambuc 		return 0;
708*ebfedea0SLionel Sambuc 	}
709*ebfedea0SLionel Sambuc 	base64->checksum = CRC24_INIT;
710*ebfedea0SLionel Sambuc 	pgp_writer_push(output, base64_writer, sig_finaliser,
711*ebfedea0SLionel Sambuc 			generic_destroyer, base64);
712*ebfedea0SLionel Sambuc 	return 1;
713*ebfedea0SLionel Sambuc }
714*ebfedea0SLionel Sambuc 
715*ebfedea0SLionel Sambuc static unsigned
armoured_message_finaliser(pgp_error_t ** errors,pgp_writer_t * writer)716*ebfedea0SLionel Sambuc armoured_message_finaliser(pgp_error_t **errors, pgp_writer_t *writer)
717*ebfedea0SLionel Sambuc {
718*ebfedea0SLionel Sambuc 	/* TODO: This is same as sig_finaliser apart from trailer. */
719*ebfedea0SLionel Sambuc 	static const char	 trailer[] =
720*ebfedea0SLionel Sambuc 			"\r\n-----END PGP MESSAGE-----\r\n";
721*ebfedea0SLionel Sambuc 	base64_t		*base64;
722*ebfedea0SLionel Sambuc 	uint8_t			 c[3];
723*ebfedea0SLionel Sambuc 
724*ebfedea0SLionel Sambuc 	base64 = pgp_writer_get_arg(writer);
725*ebfedea0SLionel Sambuc 	if (base64->pos) {
726*ebfedea0SLionel Sambuc 		if (!stacked_write(writer, &b64map[base64->t], 1, errors)) {
727*ebfedea0SLionel Sambuc 			return 0;
728*ebfedea0SLionel Sambuc 		}
729*ebfedea0SLionel Sambuc 		if (base64->pos == 1 &&
730*ebfedea0SLionel Sambuc 		    !stacked_write(writer, "==", 2, errors)) {
731*ebfedea0SLionel Sambuc 			return 0;
732*ebfedea0SLionel Sambuc 		}
733*ebfedea0SLionel Sambuc 		if (base64->pos == 2 &&
734*ebfedea0SLionel Sambuc 		    !stacked_write(writer, "=", 1, errors)) {
735*ebfedea0SLionel Sambuc 			return 0;
736*ebfedea0SLionel Sambuc 		}
737*ebfedea0SLionel Sambuc 	}
738*ebfedea0SLionel Sambuc 	/* Ready for the checksum */
739*ebfedea0SLionel Sambuc 	if (!stacked_write(writer, "\r\n=", 3, errors)) {
740*ebfedea0SLionel Sambuc 		return 0;
741*ebfedea0SLionel Sambuc 	}
742*ebfedea0SLionel Sambuc 
743*ebfedea0SLionel Sambuc 	base64->pos = 0;		/* get ready to write the checksum */
744*ebfedea0SLionel Sambuc 
745*ebfedea0SLionel Sambuc 	c[0] = base64->checksum >> 16;
746*ebfedea0SLionel Sambuc 	c[1] = base64->checksum >> 8;
747*ebfedea0SLionel Sambuc 	c[2] = base64->checksum;
748*ebfedea0SLionel Sambuc 	/* push the checksum through our own writer */
749*ebfedea0SLionel Sambuc 	if (!base64_writer(c, 3, errors, writer)) {
750*ebfedea0SLionel Sambuc 		return 0;
751*ebfedea0SLionel Sambuc 	}
752*ebfedea0SLionel Sambuc 
753*ebfedea0SLionel Sambuc 	return stacked_write(writer, trailer, (unsigned)strlen(trailer), errors);
754*ebfedea0SLionel Sambuc }
755*ebfedea0SLionel Sambuc 
756*ebfedea0SLionel Sambuc /**
757*ebfedea0SLionel Sambuc  \ingroup Core_WritersNext
758*ebfedea0SLionel Sambuc  \brief Write a PGP MESSAGE
759*ebfedea0SLionel Sambuc  \todo replace with generic function
760*ebfedea0SLionel Sambuc */
761*ebfedea0SLionel Sambuc void
pgp_writer_push_armor_msg(pgp_output_t * output)762*ebfedea0SLionel Sambuc pgp_writer_push_armor_msg(pgp_output_t *output)
763*ebfedea0SLionel Sambuc {
764*ebfedea0SLionel Sambuc 	static const char	 header[] = "-----BEGIN PGP MESSAGE-----\r\n";
765*ebfedea0SLionel Sambuc 	linebreak_t		*linebreak;
766*ebfedea0SLionel Sambuc 	base64_t		*base64;
767*ebfedea0SLionel Sambuc 
768*ebfedea0SLionel Sambuc 	pgp_write(output, header, (unsigned)(sizeof(header) - 1));
769*ebfedea0SLionel Sambuc 	pgp_write(output, "\r\n", 2);
770*ebfedea0SLionel Sambuc 	if ((linebreak = calloc(1, sizeof(*linebreak))) == NULL) {
771*ebfedea0SLionel Sambuc 		(void) fprintf(stderr,
772*ebfedea0SLionel Sambuc 			"pgp_writer_push_armor_msg: bad lb alloc\n");
773*ebfedea0SLionel Sambuc 		return;
774*ebfedea0SLionel Sambuc 	}
775*ebfedea0SLionel Sambuc 	pgp_writer_push(output, linebreak_writer, NULL,
776*ebfedea0SLionel Sambuc 		generic_destroyer,
777*ebfedea0SLionel Sambuc 		linebreak);
778*ebfedea0SLionel Sambuc 	if ((base64 = calloc(1, sizeof(*base64))) == NULL) {
779*ebfedea0SLionel Sambuc 		(void) fprintf(stderr,
780*ebfedea0SLionel Sambuc 			"pgp_writer_push_armor_msg: bad alloc\n");
781*ebfedea0SLionel Sambuc 		return;
782*ebfedea0SLionel Sambuc 	}
783*ebfedea0SLionel Sambuc 	base64->checksum = CRC24_INIT;
784*ebfedea0SLionel Sambuc 	pgp_writer_push(output, base64_writer,
785*ebfedea0SLionel Sambuc 		armoured_message_finaliser, generic_destroyer,
786*ebfedea0SLionel Sambuc 		base64);
787*ebfedea0SLionel Sambuc }
788*ebfedea0SLionel Sambuc 
789*ebfedea0SLionel Sambuc static unsigned
armoured_finaliser(pgp_armor_type_t type,pgp_error_t ** errors,pgp_writer_t * writer)790*ebfedea0SLionel Sambuc armoured_finaliser(pgp_armor_type_t type,
791*ebfedea0SLionel Sambuc 			pgp_error_t **errors,
792*ebfedea0SLionel Sambuc 			pgp_writer_t *writer)
793*ebfedea0SLionel Sambuc {
794*ebfedea0SLionel Sambuc 	static const char     tail_pubkey[] =
795*ebfedea0SLionel Sambuc 			"\r\n-----END PGP PUBLIC KEY BLOCK-----\r\n";
796*ebfedea0SLionel Sambuc 	static const char     tail_private_key[] =
797*ebfedea0SLionel Sambuc 			"\r\n-----END PGP PRIVATE KEY BLOCK-----\r\n";
798*ebfedea0SLionel Sambuc 	const char		*tail = NULL;
799*ebfedea0SLionel Sambuc 	unsigned		 tailsize = 0;
800*ebfedea0SLionel Sambuc 	base64_t		*base64;
801*ebfedea0SLionel Sambuc 	uint8_t		 	 c[3];
802*ebfedea0SLionel Sambuc 
803*ebfedea0SLionel Sambuc 	switch (type) {
804*ebfedea0SLionel Sambuc 	case PGP_PGP_PUBLIC_KEY_BLOCK:
805*ebfedea0SLionel Sambuc 		tail = tail_pubkey;
806*ebfedea0SLionel Sambuc 		tailsize = sizeof(tail_pubkey) - 1;
807*ebfedea0SLionel Sambuc 		break;
808*ebfedea0SLionel Sambuc 
809*ebfedea0SLionel Sambuc 	case PGP_PGP_PRIVATE_KEY_BLOCK:
810*ebfedea0SLionel Sambuc 		tail = tail_private_key;
811*ebfedea0SLionel Sambuc 		tailsize = sizeof(tail_private_key) - 1;
812*ebfedea0SLionel Sambuc 		break;
813*ebfedea0SLionel Sambuc 
814*ebfedea0SLionel Sambuc 	default:
815*ebfedea0SLionel Sambuc 		(void) fprintf(stderr, "armoured_finaliser: unusual type\n");
816*ebfedea0SLionel Sambuc 		return 0;
817*ebfedea0SLionel Sambuc 	}
818*ebfedea0SLionel Sambuc 	base64 = pgp_writer_get_arg(writer);
819*ebfedea0SLionel Sambuc 	if (base64->pos) {
820*ebfedea0SLionel Sambuc 		if (!stacked_write(writer, &b64map[base64->t], 1,
821*ebfedea0SLionel Sambuc 					errors)) {
822*ebfedea0SLionel Sambuc 			return 0;
823*ebfedea0SLionel Sambuc 		}
824*ebfedea0SLionel Sambuc 		if (base64->pos == 1 && !stacked_write(writer, "==", 2,
825*ebfedea0SLionel Sambuc 				errors)) {
826*ebfedea0SLionel Sambuc 			return 0;
827*ebfedea0SLionel Sambuc 		}
828*ebfedea0SLionel Sambuc 		if (base64->pos == 2 && !stacked_write(writer, "=", 1,
829*ebfedea0SLionel Sambuc 				errors)) {
830*ebfedea0SLionel Sambuc 			return 0;
831*ebfedea0SLionel Sambuc 		}
832*ebfedea0SLionel Sambuc 	}
833*ebfedea0SLionel Sambuc 	/* Ready for the checksum */
834*ebfedea0SLionel Sambuc 	if (!stacked_write(writer, "\r\n=", 3, errors)) {
835*ebfedea0SLionel Sambuc 		return 0;
836*ebfedea0SLionel Sambuc 	}
837*ebfedea0SLionel Sambuc 	base64->pos = 0;		/* get ready to write the checksum */
838*ebfedea0SLionel Sambuc 	c[0] = base64->checksum >> 16;
839*ebfedea0SLionel Sambuc 	c[1] = base64->checksum >> 8;
840*ebfedea0SLionel Sambuc 	c[2] = base64->checksum;
841*ebfedea0SLionel Sambuc 	/* push the checksum through our own writer */
842*ebfedea0SLionel Sambuc 	if (!base64_writer(c, 3, errors, writer)) {
843*ebfedea0SLionel Sambuc 		return 0;
844*ebfedea0SLionel Sambuc 	}
845*ebfedea0SLionel Sambuc 	return stacked_write(writer, tail, tailsize, errors);
846*ebfedea0SLionel Sambuc }
847*ebfedea0SLionel Sambuc 
848*ebfedea0SLionel Sambuc static unsigned
armored_pubkey_fini(pgp_error_t ** errors,pgp_writer_t * writer)849*ebfedea0SLionel Sambuc armored_pubkey_fini(pgp_error_t **errors, pgp_writer_t *writer)
850*ebfedea0SLionel Sambuc {
851*ebfedea0SLionel Sambuc 	return armoured_finaliser(PGP_PGP_PUBLIC_KEY_BLOCK, errors, writer);
852*ebfedea0SLionel Sambuc }
853*ebfedea0SLionel Sambuc 
854*ebfedea0SLionel Sambuc static unsigned
armored_privkey_fini(pgp_error_t ** errors,pgp_writer_t * writer)855*ebfedea0SLionel Sambuc armored_privkey_fini(pgp_error_t **errors, pgp_writer_t *writer)
856*ebfedea0SLionel Sambuc {
857*ebfedea0SLionel Sambuc 	return armoured_finaliser(PGP_PGP_PRIVATE_KEY_BLOCK, errors, writer);
858*ebfedea0SLionel Sambuc }
859*ebfedea0SLionel Sambuc 
860*ebfedea0SLionel Sambuc /* \todo use this for other armoured types */
861*ebfedea0SLionel Sambuc /**
862*ebfedea0SLionel Sambuc  \ingroup Core_WritersNext
863*ebfedea0SLionel Sambuc  \brief Push Armoured Writer on stack (generic)
864*ebfedea0SLionel Sambuc */
865*ebfedea0SLionel Sambuc void
pgp_writer_push_armoured(pgp_output_t * output,pgp_armor_type_t type)866*ebfedea0SLionel Sambuc pgp_writer_push_armoured(pgp_output_t *output, pgp_armor_type_t type)
867*ebfedea0SLionel Sambuc {
868*ebfedea0SLionel Sambuc 	static char     hdr_pubkey[] =
869*ebfedea0SLionel Sambuc 			"-----BEGIN PGP PUBLIC KEY BLOCK-----\r\nVersion: "
870*ebfedea0SLionel Sambuc 			NETPGP_VERSION_STRING
871*ebfedea0SLionel Sambuc 			"\r\n\r\n";
872*ebfedea0SLionel Sambuc 	static char     hdr_private_key[] =
873*ebfedea0SLionel Sambuc 			"-----BEGIN PGP PRIVATE KEY BLOCK-----\r\nVersion: "
874*ebfedea0SLionel Sambuc 			NETPGP_VERSION_STRING
875*ebfedea0SLionel Sambuc 			"\r\n\r\n";
876*ebfedea0SLionel Sambuc 	unsigned    	 hdrsize = 0;
877*ebfedea0SLionel Sambuc 	unsigned	(*finaliser) (pgp_error_t **, pgp_writer_t *);
878*ebfedea0SLionel Sambuc 	base64_t	*base64;
879*ebfedea0SLionel Sambuc 	linebreak_t	*linebreak;
880*ebfedea0SLionel Sambuc 	char           *header = NULL;
881*ebfedea0SLionel Sambuc 
882*ebfedea0SLionel Sambuc 	finaliser = NULL;
883*ebfedea0SLionel Sambuc 	switch (type) {
884*ebfedea0SLionel Sambuc 	case PGP_PGP_PUBLIC_KEY_BLOCK:
885*ebfedea0SLionel Sambuc 		header = hdr_pubkey;
886*ebfedea0SLionel Sambuc 		hdrsize = sizeof(hdr_pubkey) - 1;
887*ebfedea0SLionel Sambuc 		finaliser = armored_pubkey_fini;
888*ebfedea0SLionel Sambuc 		break;
889*ebfedea0SLionel Sambuc 
890*ebfedea0SLionel Sambuc 	case PGP_PGP_PRIVATE_KEY_BLOCK:
891*ebfedea0SLionel Sambuc 		header = hdr_private_key;
892*ebfedea0SLionel Sambuc 		hdrsize = sizeof(hdr_private_key) - 1;
893*ebfedea0SLionel Sambuc 		finaliser = armored_privkey_fini;
894*ebfedea0SLionel Sambuc 		break;
895*ebfedea0SLionel Sambuc 
896*ebfedea0SLionel Sambuc 	default:
897*ebfedea0SLionel Sambuc 		(void) fprintf(stderr,
898*ebfedea0SLionel Sambuc 			"pgp_writer_push_armoured: unusual type\n");
899*ebfedea0SLionel Sambuc 		return;
900*ebfedea0SLionel Sambuc 	}
901*ebfedea0SLionel Sambuc 	if ((linebreak = calloc(1, sizeof(*linebreak))) == NULL) {
902*ebfedea0SLionel Sambuc 		(void) fprintf(stderr,
903*ebfedea0SLionel Sambuc 			"pgp_writer_push_armoured: bad alloc\n");
904*ebfedea0SLionel Sambuc 		return;
905*ebfedea0SLionel Sambuc 	}
906*ebfedea0SLionel Sambuc 	pgp_write(output, header, hdrsize);
907*ebfedea0SLionel Sambuc 	pgp_writer_push(output, linebreak_writer, NULL,
908*ebfedea0SLionel Sambuc 			generic_destroyer,
909*ebfedea0SLionel Sambuc 			linebreak);
910*ebfedea0SLionel Sambuc 	if ((base64 = calloc(1, sizeof(*base64))) == NULL) {
911*ebfedea0SLionel Sambuc 		(void) fprintf(stderr,
912*ebfedea0SLionel Sambuc 			"pgp_writer_push_armoured: bad alloc\n");
913*ebfedea0SLionel Sambuc 		return;
914*ebfedea0SLionel Sambuc 	}
915*ebfedea0SLionel Sambuc 	base64->checksum = CRC24_INIT;
916*ebfedea0SLionel Sambuc 	pgp_writer_push(output, base64_writer, finaliser,
917*ebfedea0SLionel Sambuc 			generic_destroyer, base64);
918*ebfedea0SLionel Sambuc }
919*ebfedea0SLionel Sambuc 
920*ebfedea0SLionel Sambuc /**************************************************************************/
921*ebfedea0SLionel Sambuc 
922*ebfedea0SLionel Sambuc typedef struct {
923*ebfedea0SLionel Sambuc 	pgp_crypt_t    *crypt;
924*ebfedea0SLionel Sambuc 	int             free_crypt;
925*ebfedea0SLionel Sambuc } crypt_t;
926*ebfedea0SLionel Sambuc 
927*ebfedea0SLionel Sambuc /*
928*ebfedea0SLionel Sambuc  * This writer simply takes plaintext as input,
929*ebfedea0SLionel Sambuc  * encrypts it with the given key
930*ebfedea0SLionel Sambuc  * and outputs the resulting encrypted text
931*ebfedea0SLionel Sambuc  */
932*ebfedea0SLionel Sambuc static unsigned
encrypt_writer(const uint8_t * src,unsigned len,pgp_error_t ** errors,pgp_writer_t * writer)933*ebfedea0SLionel Sambuc encrypt_writer(const uint8_t *src,
934*ebfedea0SLionel Sambuc 	       unsigned len,
935*ebfedea0SLionel Sambuc 	       pgp_error_t **errors,
936*ebfedea0SLionel Sambuc 	       pgp_writer_t *writer)
937*ebfedea0SLionel Sambuc {
938*ebfedea0SLionel Sambuc #define BUFSZ 1024		/* arbitrary number */
939*ebfedea0SLionel Sambuc 	uint8_t		encbuf[BUFSZ];
940*ebfedea0SLionel Sambuc 	unsigned        remaining;
941*ebfedea0SLionel Sambuc 	unsigned        done = 0;
942*ebfedea0SLionel Sambuc 	crypt_t		*pgp_encrypt;
943*ebfedea0SLionel Sambuc 
944*ebfedea0SLionel Sambuc 	remaining = len;
945*ebfedea0SLionel Sambuc 	pgp_encrypt = (crypt_t *) pgp_writer_get_arg(writer);
946*ebfedea0SLionel Sambuc 	if (!pgp_is_sa_supported(pgp_encrypt->crypt->alg)) {
947*ebfedea0SLionel Sambuc 		(void) fprintf(stderr, "encrypt_writer: not supported\n");
948*ebfedea0SLionel Sambuc 		return 0;
949*ebfedea0SLionel Sambuc 	}
950*ebfedea0SLionel Sambuc 	while (remaining > 0) {
951*ebfedea0SLionel Sambuc 		unsigned        size = (remaining < BUFSZ) ? remaining : BUFSZ;
952*ebfedea0SLionel Sambuc 
953*ebfedea0SLionel Sambuc 		/* memcpy(buf,src,size); // \todo copy needed here? */
954*ebfedea0SLionel Sambuc 		pgp_encrypt->crypt->cfb_encrypt(pgp_encrypt->crypt, encbuf,
955*ebfedea0SLionel Sambuc 					src + done, size);
956*ebfedea0SLionel Sambuc 
957*ebfedea0SLionel Sambuc 		if (pgp_get_debug_level(__FILE__)) {
958*ebfedea0SLionel Sambuc 			hexdump(stderr, "unencrypted", &src[done], 16);
959*ebfedea0SLionel Sambuc 			hexdump(stderr, "encrypted", encbuf, 16);
960*ebfedea0SLionel Sambuc 		}
961*ebfedea0SLionel Sambuc 		if (!stacked_write(writer, encbuf, size, errors)) {
962*ebfedea0SLionel Sambuc 			if (pgp_get_debug_level(__FILE__)) {
963*ebfedea0SLionel Sambuc 				fprintf(stderr,
964*ebfedea0SLionel Sambuc 					"encrypted_writer: stacked write\n");
965*ebfedea0SLionel Sambuc 			}
966*ebfedea0SLionel Sambuc 			return 0;
967*ebfedea0SLionel Sambuc 		}
968*ebfedea0SLionel Sambuc 		remaining -= size;
969*ebfedea0SLionel Sambuc 		done += size;
970*ebfedea0SLionel Sambuc 	}
971*ebfedea0SLionel Sambuc 
972*ebfedea0SLionel Sambuc 	return 1;
973*ebfedea0SLionel Sambuc }
974*ebfedea0SLionel Sambuc 
975*ebfedea0SLionel Sambuc static void
encrypt_destroyer(pgp_writer_t * writer)976*ebfedea0SLionel Sambuc encrypt_destroyer(pgp_writer_t *writer)
977*ebfedea0SLionel Sambuc {
978*ebfedea0SLionel Sambuc 	crypt_t    *pgp_encrypt;
979*ebfedea0SLionel Sambuc 
980*ebfedea0SLionel Sambuc 	pgp_encrypt = (crypt_t *) pgp_writer_get_arg(writer);
981*ebfedea0SLionel Sambuc 	if (pgp_encrypt->free_crypt) {
982*ebfedea0SLionel Sambuc 		free(pgp_encrypt->crypt);
983*ebfedea0SLionel Sambuc 	}
984*ebfedea0SLionel Sambuc 	free(pgp_encrypt);
985*ebfedea0SLionel Sambuc }
986*ebfedea0SLionel Sambuc 
987*ebfedea0SLionel Sambuc /**
988*ebfedea0SLionel Sambuc \ingroup Core_WritersNext
989*ebfedea0SLionel Sambuc \brief Push Encrypted Writer onto stack (create SE packets)
990*ebfedea0SLionel Sambuc */
991*ebfedea0SLionel Sambuc void
pgp_push_enc_crypt(pgp_output_t * output,pgp_crypt_t * pgp_crypt)992*ebfedea0SLionel Sambuc pgp_push_enc_crypt(pgp_output_t *output, pgp_crypt_t *pgp_crypt)
993*ebfedea0SLionel Sambuc {
994*ebfedea0SLionel Sambuc 	/* Create encrypt to be used with this writer */
995*ebfedea0SLionel Sambuc 	/* Remember to free this in the destroyer */
996*ebfedea0SLionel Sambuc 	crypt_t    *pgp_encrypt;
997*ebfedea0SLionel Sambuc 
998*ebfedea0SLionel Sambuc 	if ((pgp_encrypt = calloc(1, sizeof(*pgp_encrypt))) == NULL) {
999*ebfedea0SLionel Sambuc 		(void) fprintf(stderr, "pgp_push_enc_crypt: bad alloc\n");
1000*ebfedea0SLionel Sambuc 	} else {
1001*ebfedea0SLionel Sambuc 		/* Setup the encrypt */
1002*ebfedea0SLionel Sambuc 		pgp_encrypt->crypt = pgp_crypt;
1003*ebfedea0SLionel Sambuc 		pgp_encrypt->free_crypt = 0;
1004*ebfedea0SLionel Sambuc 		/* And push writer on stack */
1005*ebfedea0SLionel Sambuc 		pgp_writer_push(output, encrypt_writer, NULL,
1006*ebfedea0SLionel Sambuc 			encrypt_destroyer, pgp_encrypt);
1007*ebfedea0SLionel Sambuc 	}
1008*ebfedea0SLionel Sambuc }
1009*ebfedea0SLionel Sambuc 
1010*ebfedea0SLionel Sambuc /**************************************************************************/
1011*ebfedea0SLionel Sambuc 
1012*ebfedea0SLionel Sambuc typedef struct {
1013*ebfedea0SLionel Sambuc 	pgp_crypt_t    *crypt;
1014*ebfedea0SLionel Sambuc } encrypt_se_ip_t;
1015*ebfedea0SLionel Sambuc 
1016*ebfedea0SLionel Sambuc static unsigned	encrypt_se_ip_writer(const uint8_t *,
1017*ebfedea0SLionel Sambuc 		     unsigned,
1018*ebfedea0SLionel Sambuc 		     pgp_error_t **,
1019*ebfedea0SLionel Sambuc 		     pgp_writer_t *);
1020*ebfedea0SLionel Sambuc static void     encrypt_se_ip_destroyer(pgp_writer_t *);
1021*ebfedea0SLionel Sambuc 
1022*ebfedea0SLionel Sambuc /* */
1023*ebfedea0SLionel Sambuc 
1024*ebfedea0SLionel Sambuc /**
1025*ebfedea0SLionel Sambuc \ingroup Core_WritersNext
1026*ebfedea0SLionel Sambuc \brief Push Encrypted SE IP Writer onto stack
1027*ebfedea0SLionel Sambuc */
1028*ebfedea0SLionel Sambuc int
pgp_push_enc_se_ip(pgp_output_t * output,const pgp_key_t * pubkey,const char * cipher)1029*ebfedea0SLionel Sambuc pgp_push_enc_se_ip(pgp_output_t *output, const pgp_key_t *pubkey, const char *cipher)
1030*ebfedea0SLionel Sambuc {
1031*ebfedea0SLionel Sambuc 	pgp_pk_sesskey_t *encrypted_pk_sesskey;
1032*ebfedea0SLionel Sambuc 	encrypt_se_ip_t *se_ip;
1033*ebfedea0SLionel Sambuc 	pgp_crypt_t	*encrypted;
1034*ebfedea0SLionel Sambuc 	uint8_t		*iv;
1035*ebfedea0SLionel Sambuc 
1036*ebfedea0SLionel Sambuc 	if ((se_ip = calloc(1, sizeof(*se_ip))) == NULL) {
1037*ebfedea0SLionel Sambuc 		(void) fprintf(stderr, "pgp_push_enc_se_ip: bad alloc\n");
1038*ebfedea0SLionel Sambuc 		return 0;
1039*ebfedea0SLionel Sambuc 	}
1040*ebfedea0SLionel Sambuc 
1041*ebfedea0SLionel Sambuc 	/* Create and write encrypted PK session key */
1042*ebfedea0SLionel Sambuc 	if ((encrypted_pk_sesskey = pgp_create_pk_sesskey(pubkey, cipher)) == NULL) {
1043*ebfedea0SLionel Sambuc 		(void) fprintf(stderr, "pgp_push_enc_se_ip: null pk sesskey\n");
1044*ebfedea0SLionel Sambuc 		return 0;
1045*ebfedea0SLionel Sambuc 	}
1046*ebfedea0SLionel Sambuc 	pgp_write_pk_sesskey(output, encrypted_pk_sesskey);
1047*ebfedea0SLionel Sambuc 
1048*ebfedea0SLionel Sambuc 	/* Setup the se_ip */
1049*ebfedea0SLionel Sambuc 	if ((encrypted = calloc(1, sizeof(*encrypted))) == NULL) {
1050*ebfedea0SLionel Sambuc 		free(se_ip);
1051*ebfedea0SLionel Sambuc 		(void) fprintf(stderr, "pgp_push_enc_se_ip: bad alloc\n");
1052*ebfedea0SLionel Sambuc 		return 0;
1053*ebfedea0SLionel Sambuc 	}
1054*ebfedea0SLionel Sambuc 	pgp_crypt_any(encrypted, encrypted_pk_sesskey->symm_alg);
1055*ebfedea0SLionel Sambuc 	if ((iv = calloc(1, encrypted->blocksize)) == NULL) {
1056*ebfedea0SLionel Sambuc 		free(se_ip);
1057*ebfedea0SLionel Sambuc 		free(encrypted);
1058*ebfedea0SLionel Sambuc 		(void) fprintf(stderr, "pgp_push_enc_se_ip: bad alloc\n");
1059*ebfedea0SLionel Sambuc 		return 0;
1060*ebfedea0SLionel Sambuc 	}
1061*ebfedea0SLionel Sambuc 	encrypted->set_iv(encrypted, iv);
1062*ebfedea0SLionel Sambuc 	encrypted->set_crypt_key(encrypted, &encrypted_pk_sesskey->key[0]);
1063*ebfedea0SLionel Sambuc 	pgp_encrypt_init(encrypted);
1064*ebfedea0SLionel Sambuc 
1065*ebfedea0SLionel Sambuc 	se_ip->crypt = encrypted;
1066*ebfedea0SLionel Sambuc 
1067*ebfedea0SLionel Sambuc 	/* And push writer on stack */
1068*ebfedea0SLionel Sambuc 	pgp_writer_push(output, encrypt_se_ip_writer, NULL,
1069*ebfedea0SLionel Sambuc 			encrypt_se_ip_destroyer, se_ip);
1070*ebfedea0SLionel Sambuc 	/* tidy up */
1071*ebfedea0SLionel Sambuc 	free(encrypted_pk_sesskey);
1072*ebfedea0SLionel Sambuc 	free(iv);
1073*ebfedea0SLionel Sambuc 	return 1;
1074*ebfedea0SLionel Sambuc }
1075*ebfedea0SLionel Sambuc 
1076*ebfedea0SLionel Sambuc static unsigned
encrypt_se_ip_writer(const uint8_t * src,unsigned len,pgp_error_t ** errors,pgp_writer_t * writer)1077*ebfedea0SLionel Sambuc encrypt_se_ip_writer(const uint8_t *src,
1078*ebfedea0SLionel Sambuc 		     unsigned len,
1079*ebfedea0SLionel Sambuc 		     pgp_error_t **errors,
1080*ebfedea0SLionel Sambuc 		     pgp_writer_t *writer)
1081*ebfedea0SLionel Sambuc {
1082*ebfedea0SLionel Sambuc 	const unsigned	 bufsz = 128;
1083*ebfedea0SLionel Sambuc 	encrypt_se_ip_t	*se_ip = pgp_writer_get_arg(writer);
1084*ebfedea0SLionel Sambuc 	pgp_output_t	*litoutput;
1085*ebfedea0SLionel Sambuc 	pgp_output_t	*zoutput;
1086*ebfedea0SLionel Sambuc 	pgp_output_t	*output;
1087*ebfedea0SLionel Sambuc 	pgp_memory_t	*litmem;
1088*ebfedea0SLionel Sambuc 	pgp_memory_t	*zmem;
1089*ebfedea0SLionel Sambuc 	pgp_memory_t	*localmem;
1090*ebfedea0SLionel Sambuc 	unsigned	 ret = 1;
1091*ebfedea0SLionel Sambuc 
1092*ebfedea0SLionel Sambuc 	pgp_setup_memory_write(&litoutput, &litmem, bufsz);
1093*ebfedea0SLionel Sambuc 	pgp_setup_memory_write(&zoutput, &zmem, bufsz);
1094*ebfedea0SLionel Sambuc 	pgp_setup_memory_write(&output, &localmem, bufsz);
1095*ebfedea0SLionel Sambuc 
1096*ebfedea0SLionel Sambuc 	/* create literal data packet from source data */
1097*ebfedea0SLionel Sambuc 	pgp_write_litdata(litoutput, src, (const int)len, PGP_LDT_BINARY);
1098*ebfedea0SLionel Sambuc 	if (pgp_mem_len(litmem) <= len) {
1099*ebfedea0SLionel Sambuc 		(void) fprintf(stderr, "encrypt_se_ip_writer: bad len\n");
1100*ebfedea0SLionel Sambuc 		return 0;
1101*ebfedea0SLionel Sambuc 	}
1102*ebfedea0SLionel Sambuc 
1103*ebfedea0SLionel Sambuc 	/* create compressed packet from literal data packet */
1104*ebfedea0SLionel Sambuc 	pgp_writez(zoutput, pgp_mem_data(litmem), (unsigned)pgp_mem_len(litmem));
1105*ebfedea0SLionel Sambuc 
1106*ebfedea0SLionel Sambuc 	/* create SE IP packet set from this compressed literal data */
1107*ebfedea0SLionel Sambuc 	pgp_write_se_ip_pktset(output, pgp_mem_data(zmem),
1108*ebfedea0SLionel Sambuc 			       (unsigned)pgp_mem_len(zmem),
1109*ebfedea0SLionel Sambuc 			       se_ip->crypt);
1110*ebfedea0SLionel Sambuc 	if (pgp_mem_len(localmem) <= pgp_mem_len(zmem)) {
1111*ebfedea0SLionel Sambuc 		(void) fprintf(stderr,
1112*ebfedea0SLionel Sambuc 				"encrypt_se_ip_writer: bad comp len\n");
1113*ebfedea0SLionel Sambuc 		return 0;
1114*ebfedea0SLionel Sambuc 	}
1115*ebfedea0SLionel Sambuc 
1116*ebfedea0SLionel Sambuc 	/* now write memory to next writer */
1117*ebfedea0SLionel Sambuc 	ret = stacked_write(writer, pgp_mem_data(localmem),
1118*ebfedea0SLionel Sambuc 				(unsigned)pgp_mem_len(localmem), errors);
1119*ebfedea0SLionel Sambuc 
1120*ebfedea0SLionel Sambuc 	pgp_memory_free(localmem);
1121*ebfedea0SLionel Sambuc 	pgp_memory_free(zmem);
1122*ebfedea0SLionel Sambuc 	pgp_memory_free(litmem);
1123*ebfedea0SLionel Sambuc 
1124*ebfedea0SLionel Sambuc 	return ret;
1125*ebfedea0SLionel Sambuc }
1126*ebfedea0SLionel Sambuc 
1127*ebfedea0SLionel Sambuc static void
encrypt_se_ip_destroyer(pgp_writer_t * writer)1128*ebfedea0SLionel Sambuc encrypt_se_ip_destroyer(pgp_writer_t *writer)
1129*ebfedea0SLionel Sambuc {
1130*ebfedea0SLionel Sambuc 	encrypt_se_ip_t	*se_ip;
1131*ebfedea0SLionel Sambuc 
1132*ebfedea0SLionel Sambuc 	se_ip = pgp_writer_get_arg(writer);
1133*ebfedea0SLionel Sambuc 	free(se_ip->crypt);
1134*ebfedea0SLionel Sambuc 	free(se_ip);
1135*ebfedea0SLionel Sambuc }
1136*ebfedea0SLionel Sambuc 
1137*ebfedea0SLionel Sambuc unsigned
pgp_write_se_ip_pktset(pgp_output_t * output,const uint8_t * data,const unsigned len,pgp_crypt_t * crypted)1138*ebfedea0SLionel Sambuc pgp_write_se_ip_pktset(pgp_output_t *output,
1139*ebfedea0SLionel Sambuc 			const uint8_t *data,
1140*ebfedea0SLionel Sambuc 			const unsigned len,
1141*ebfedea0SLionel Sambuc 			pgp_crypt_t *crypted)
1142*ebfedea0SLionel Sambuc {
1143*ebfedea0SLionel Sambuc 	pgp_output_t	*mdcoutput;
1144*ebfedea0SLionel Sambuc 	pgp_memory_t	*mdc;
1145*ebfedea0SLionel Sambuc 	uint8_t		 hashed[PGP_SHA1_HASH_SIZE];
1146*ebfedea0SLionel Sambuc 	uint8_t		*preamble;
1147*ebfedea0SLionel Sambuc 	const size_t	 mdcsize = 1 + 1 + PGP_SHA1_HASH_SIZE;
1148*ebfedea0SLionel Sambuc 	size_t		 preamblesize;
1149*ebfedea0SLionel Sambuc 	size_t		 bufsize;
1150*ebfedea0SLionel Sambuc 
1151*ebfedea0SLionel Sambuc 	preamblesize = crypted->blocksize + 2;
1152*ebfedea0SLionel Sambuc 	if ((preamble = calloc(1, preamblesize)) == NULL) {
1153*ebfedea0SLionel Sambuc 		(void) fprintf(stderr, "pgp_write_se_ip_pktset: bad alloc\n");
1154*ebfedea0SLionel Sambuc 		return 0;
1155*ebfedea0SLionel Sambuc 	}
1156*ebfedea0SLionel Sambuc 	bufsize = preamblesize + len + mdcsize;
1157*ebfedea0SLionel Sambuc 
1158*ebfedea0SLionel Sambuc 	if (!pgp_write_ptag(output, PGP_PTAG_CT_SE_IP_DATA) ||
1159*ebfedea0SLionel Sambuc 	    !pgp_write_length(output, (unsigned)(1 + bufsize)) ||
1160*ebfedea0SLionel Sambuc 	    !pgp_write_scalar(output, PGP_SE_IP_DATA_VERSION, 1)) {
1161*ebfedea0SLionel Sambuc 		free(preamble);
1162*ebfedea0SLionel Sambuc 		return 0;
1163*ebfedea0SLionel Sambuc 	}
1164*ebfedea0SLionel Sambuc 	pgp_random(preamble, crypted->blocksize);
1165*ebfedea0SLionel Sambuc 	preamble[crypted->blocksize] = preamble[crypted->blocksize - 2];
1166*ebfedea0SLionel Sambuc 	preamble[crypted->blocksize + 1] = preamble[crypted->blocksize - 1];
1167*ebfedea0SLionel Sambuc 
1168*ebfedea0SLionel Sambuc 	if (pgp_get_debug_level(__FILE__)) {
1169*ebfedea0SLionel Sambuc 		hexdump(stderr, "preamble", preamble, preamblesize);
1170*ebfedea0SLionel Sambuc 	}
1171*ebfedea0SLionel Sambuc 
1172*ebfedea0SLionel Sambuc 	/* now construct MDC packet and add to the end of the buffer */
1173*ebfedea0SLionel Sambuc 	pgp_setup_memory_write(&mdcoutput, &mdc, mdcsize);
1174*ebfedea0SLionel Sambuc 	pgp_calc_mdc_hash(preamble, preamblesize, data, len, hashed);
1175*ebfedea0SLionel Sambuc 	pgp_write_mdc(mdcoutput, hashed);
1176*ebfedea0SLionel Sambuc 
1177*ebfedea0SLionel Sambuc 	if (pgp_get_debug_level(__FILE__)) {
1178*ebfedea0SLionel Sambuc 		hexdump(stderr, "plaintext", data, len);
1179*ebfedea0SLionel Sambuc 		hexdump(stderr, "mdc", pgp_mem_data(mdc), PGP_SHA1_HASH_SIZE + 1 + 1);
1180*ebfedea0SLionel Sambuc 	}
1181*ebfedea0SLionel Sambuc 
1182*ebfedea0SLionel Sambuc 	/* and write it out */
1183*ebfedea0SLionel Sambuc 	pgp_push_enc_crypt(output, crypted);
1184*ebfedea0SLionel Sambuc 	if (pgp_get_debug_level(__FILE__)) {
1185*ebfedea0SLionel Sambuc 		(void) fprintf(stderr,
1186*ebfedea0SLionel Sambuc 			"writing %" PRIsize "u + %u + %" PRIsize "u\n",
1187*ebfedea0SLionel Sambuc 			preamblesize, len, pgp_mem_len(mdc));
1188*ebfedea0SLionel Sambuc 	}
1189*ebfedea0SLionel Sambuc 	if (!pgp_write(output, preamble, (unsigned)preamblesize) ||
1190*ebfedea0SLionel Sambuc 	    !pgp_write(output, data, len) ||
1191*ebfedea0SLionel Sambuc 	    !pgp_write(output, pgp_mem_data(mdc), (unsigned)pgp_mem_len(mdc))) {
1192*ebfedea0SLionel Sambuc 		/* \todo fix cleanup here and in old code functions */
1193*ebfedea0SLionel Sambuc 		return 0;
1194*ebfedea0SLionel Sambuc 	}
1195*ebfedea0SLionel Sambuc 
1196*ebfedea0SLionel Sambuc 	pgp_writer_pop(output);
1197*ebfedea0SLionel Sambuc 
1198*ebfedea0SLionel Sambuc 	/* cleanup  */
1199*ebfedea0SLionel Sambuc 	pgp_teardown_memory_write(mdcoutput, mdc);
1200*ebfedea0SLionel Sambuc 	free(preamble);
1201*ebfedea0SLionel Sambuc 
1202*ebfedea0SLionel Sambuc 	return 1;
1203*ebfedea0SLionel Sambuc }
1204*ebfedea0SLionel Sambuc 
1205*ebfedea0SLionel Sambuc typedef struct {
1206*ebfedea0SLionel Sambuc 	int             fd;
1207*ebfedea0SLionel Sambuc } writer_fd_t;
1208*ebfedea0SLionel Sambuc 
1209*ebfedea0SLionel Sambuc static unsigned
fd_writer(const uint8_t * src,unsigned len,pgp_error_t ** errors,pgp_writer_t * writer)1210*ebfedea0SLionel Sambuc fd_writer(const uint8_t *src, unsigned len,
1211*ebfedea0SLionel Sambuc 	  pgp_error_t **errors,
1212*ebfedea0SLionel Sambuc 	  pgp_writer_t *writer)
1213*ebfedea0SLionel Sambuc {
1214*ebfedea0SLionel Sambuc 	writer_fd_t	*writerfd;
1215*ebfedea0SLionel Sambuc 	int              n;
1216*ebfedea0SLionel Sambuc 
1217*ebfedea0SLionel Sambuc 	writerfd = pgp_writer_get_arg(writer);
1218*ebfedea0SLionel Sambuc 	n = (int)write(writerfd->fd, src, len);
1219*ebfedea0SLionel Sambuc 	if (n == -1) {
1220*ebfedea0SLionel Sambuc 		PGP_SYSTEM_ERROR_1(errors, PGP_E_W_WRITE_FAILED, "write",
1221*ebfedea0SLionel Sambuc 				   "file descriptor %d", writerfd->fd);
1222*ebfedea0SLionel Sambuc 		return 0;
1223*ebfedea0SLionel Sambuc 	}
1224*ebfedea0SLionel Sambuc 	if ((unsigned) n != len) {
1225*ebfedea0SLionel Sambuc 		PGP_ERROR_1(errors, PGP_E_W_WRITE_TOO_SHORT,
1226*ebfedea0SLionel Sambuc 			    "file descriptor %d", writerfd->fd);
1227*ebfedea0SLionel Sambuc 		return 0;
1228*ebfedea0SLionel Sambuc 	}
1229*ebfedea0SLionel Sambuc 	return 1;
1230*ebfedea0SLionel Sambuc }
1231*ebfedea0SLionel Sambuc 
1232*ebfedea0SLionel Sambuc static void
writer_fd_destroyer(pgp_writer_t * writer)1233*ebfedea0SLionel Sambuc writer_fd_destroyer(pgp_writer_t *writer)
1234*ebfedea0SLionel Sambuc {
1235*ebfedea0SLionel Sambuc 	free(pgp_writer_get_arg(writer));
1236*ebfedea0SLionel Sambuc }
1237*ebfedea0SLionel Sambuc 
1238*ebfedea0SLionel Sambuc /**
1239*ebfedea0SLionel Sambuc  * \ingroup Core_WritersFirst
1240*ebfedea0SLionel Sambuc  * \brief Write to a File
1241*ebfedea0SLionel Sambuc  *
1242*ebfedea0SLionel Sambuc  * Set the writer in output to be a stock writer that writes to a file
1243*ebfedea0SLionel Sambuc  * descriptor. If another writer has already been set, then that is
1244*ebfedea0SLionel Sambuc  * first destroyed.
1245*ebfedea0SLionel Sambuc  *
1246*ebfedea0SLionel Sambuc  * \param output The output structure
1247*ebfedea0SLionel Sambuc  * \param fd The file descriptor
1248*ebfedea0SLionel Sambuc  *
1249*ebfedea0SLionel Sambuc  */
1250*ebfedea0SLionel Sambuc 
1251*ebfedea0SLionel Sambuc void
pgp_writer_set_fd(pgp_output_t * output,int fd)1252*ebfedea0SLionel Sambuc pgp_writer_set_fd(pgp_output_t *output, int fd)
1253*ebfedea0SLionel Sambuc {
1254*ebfedea0SLionel Sambuc 	writer_fd_t	*writer;
1255*ebfedea0SLionel Sambuc 
1256*ebfedea0SLionel Sambuc 	if ((writer = calloc(1, sizeof(*writer))) == NULL) {
1257*ebfedea0SLionel Sambuc 		(void) fprintf(stderr, "pgp_writer_set_fd: bad alloc\n");
1258*ebfedea0SLionel Sambuc 	} else {
1259*ebfedea0SLionel Sambuc 		writer->fd = fd;
1260*ebfedea0SLionel Sambuc 		pgp_writer_set(output, fd_writer, NULL, writer_fd_destroyer, writer);
1261*ebfedea0SLionel Sambuc 	}
1262*ebfedea0SLionel Sambuc }
1263*ebfedea0SLionel Sambuc 
1264*ebfedea0SLionel Sambuc static unsigned
memory_writer(const uint8_t * src,unsigned len,pgp_error_t ** errors,pgp_writer_t * writer)1265*ebfedea0SLionel Sambuc memory_writer(const uint8_t *src,
1266*ebfedea0SLionel Sambuc 		unsigned len,
1267*ebfedea0SLionel Sambuc 		pgp_error_t **errors,
1268*ebfedea0SLionel Sambuc 		pgp_writer_t *writer)
1269*ebfedea0SLionel Sambuc {
1270*ebfedea0SLionel Sambuc 	pgp_memory_t   *mem;
1271*ebfedea0SLionel Sambuc 
1272*ebfedea0SLionel Sambuc 	__PGP_USED(errors);
1273*ebfedea0SLionel Sambuc 	mem = pgp_writer_get_arg(writer);
1274*ebfedea0SLionel Sambuc 	pgp_memory_add(mem, src, len);
1275*ebfedea0SLionel Sambuc 	return 1;
1276*ebfedea0SLionel Sambuc }
1277*ebfedea0SLionel Sambuc 
1278*ebfedea0SLionel Sambuc /**
1279*ebfedea0SLionel Sambuc  * \ingroup Core_WritersFirst
1280*ebfedea0SLionel Sambuc  * \brief Write to memory
1281*ebfedea0SLionel Sambuc  *
1282*ebfedea0SLionel Sambuc  * Set a memory writer.
1283*ebfedea0SLionel Sambuc  *
1284*ebfedea0SLionel Sambuc  * \param output The output structure
1285*ebfedea0SLionel Sambuc  * \param mem The memory structure
1286*ebfedea0SLionel Sambuc  * \note It is the caller's responsiblity to call pgp_memory_free(mem)
1287*ebfedea0SLionel Sambuc  * \sa pgp_memory_free()
1288*ebfedea0SLionel Sambuc  */
1289*ebfedea0SLionel Sambuc 
1290*ebfedea0SLionel Sambuc void
pgp_writer_set_memory(pgp_output_t * output,pgp_memory_t * mem)1291*ebfedea0SLionel Sambuc pgp_writer_set_memory(pgp_output_t *output, pgp_memory_t *mem)
1292*ebfedea0SLionel Sambuc {
1293*ebfedea0SLionel Sambuc 	pgp_writer_set(output, memory_writer, NULL, NULL, mem);
1294*ebfedea0SLionel Sambuc }
1295*ebfedea0SLionel Sambuc 
1296*ebfedea0SLionel Sambuc /**************************************************************************/
1297*ebfedea0SLionel Sambuc 
1298*ebfedea0SLionel Sambuc typedef struct {
1299*ebfedea0SLionel Sambuc 	pgp_hash_alg_t	 hash_alg;
1300*ebfedea0SLionel Sambuc 	pgp_hash_t		 hash;
1301*ebfedea0SLionel Sambuc 	uint8_t			*hashed;
1302*ebfedea0SLionel Sambuc } skey_checksum_t;
1303*ebfedea0SLionel Sambuc 
1304*ebfedea0SLionel Sambuc static unsigned
skey_checksum_writer(const uint8_t * src,const unsigned len,pgp_error_t ** errors,pgp_writer_t * writer)1305*ebfedea0SLionel Sambuc skey_checksum_writer(const uint8_t *src,
1306*ebfedea0SLionel Sambuc 	const unsigned len,
1307*ebfedea0SLionel Sambuc 	pgp_error_t **errors,
1308*ebfedea0SLionel Sambuc 	pgp_writer_t *writer)
1309*ebfedea0SLionel Sambuc {
1310*ebfedea0SLionel Sambuc 	skey_checksum_t	*sum;
1311*ebfedea0SLionel Sambuc 	unsigned	 ret = 1;
1312*ebfedea0SLionel Sambuc 
1313*ebfedea0SLionel Sambuc 	sum = pgp_writer_get_arg(writer);
1314*ebfedea0SLionel Sambuc 	/* add contents to hash */
1315*ebfedea0SLionel Sambuc 	sum->hash.add(&sum->hash, src, len);
1316*ebfedea0SLionel Sambuc 	/* write to next stacked writer */
1317*ebfedea0SLionel Sambuc 	ret = stacked_write(writer, src, len, errors);
1318*ebfedea0SLionel Sambuc 	/* tidy up and return */
1319*ebfedea0SLionel Sambuc 	return ret;
1320*ebfedea0SLionel Sambuc }
1321*ebfedea0SLionel Sambuc 
1322*ebfedea0SLionel Sambuc static unsigned
skey_checksum_finaliser(pgp_error_t ** errors,pgp_writer_t * writer)1323*ebfedea0SLionel Sambuc skey_checksum_finaliser(pgp_error_t **errors, pgp_writer_t *writer)
1324*ebfedea0SLionel Sambuc {
1325*ebfedea0SLionel Sambuc 	skey_checksum_t *sum;
1326*ebfedea0SLionel Sambuc 
1327*ebfedea0SLionel Sambuc 	sum = pgp_writer_get_arg(writer);
1328*ebfedea0SLionel Sambuc 	if (errors && *errors) {
1329*ebfedea0SLionel Sambuc 		printf("errors in skey_checksum_finaliser\n");
1330*ebfedea0SLionel Sambuc 	}
1331*ebfedea0SLionel Sambuc 	(*sum->hash.finish)(&sum->hash, sum->hashed);
1332*ebfedea0SLionel Sambuc 	return 1;
1333*ebfedea0SLionel Sambuc }
1334*ebfedea0SLionel Sambuc 
1335*ebfedea0SLionel Sambuc static void
skey_checksum_destroyer(pgp_writer_t * writer)1336*ebfedea0SLionel Sambuc skey_checksum_destroyer(pgp_writer_t *writer)
1337*ebfedea0SLionel Sambuc {
1338*ebfedea0SLionel Sambuc 	skey_checksum_t *sum;
1339*ebfedea0SLionel Sambuc 
1340*ebfedea0SLionel Sambuc 	sum = pgp_writer_get_arg(writer);
1341*ebfedea0SLionel Sambuc 	free(sum);
1342*ebfedea0SLionel Sambuc }
1343*ebfedea0SLionel Sambuc 
1344*ebfedea0SLionel Sambuc /**
1345*ebfedea0SLionel Sambuc \ingroup Core_WritersNext
1346*ebfedea0SLionel Sambuc \param output
1347*ebfedea0SLionel Sambuc \param seckey
1348*ebfedea0SLionel Sambuc */
1349*ebfedea0SLionel Sambuc void
pgp_push_checksum_writer(pgp_output_t * output,pgp_seckey_t * seckey)1350*ebfedea0SLionel Sambuc pgp_push_checksum_writer(pgp_output_t *output, pgp_seckey_t *seckey)
1351*ebfedea0SLionel Sambuc {
1352*ebfedea0SLionel Sambuc 	/* XXX: push a SHA-1 checksum writer (and change s2k to 254). */
1353*ebfedea0SLionel Sambuc 	skey_checksum_t *sum;
1354*ebfedea0SLionel Sambuc 	unsigned	 hashsize;
1355*ebfedea0SLionel Sambuc 
1356*ebfedea0SLionel Sambuc 	if ((sum = calloc(1, sizeof(*sum))) == NULL) {
1357*ebfedea0SLionel Sambuc 		(void) fprintf(stderr,
1358*ebfedea0SLionel Sambuc 			"pgp_push_checksum_writer: bad alloc\n");
1359*ebfedea0SLionel Sambuc 	} else {
1360*ebfedea0SLionel Sambuc 		/* configure the arg */
1361*ebfedea0SLionel Sambuc 		/* Hardcoded SHA1 for just now */
1362*ebfedea0SLionel Sambuc 		sum->hash_alg = PGP_HASH_SHA1;
1363*ebfedea0SLionel Sambuc 		hashsize = pgp_hash_size(sum->hash_alg);
1364*ebfedea0SLionel Sambuc 		if ((sum->hashed = seckey->checkhash) == NULL) {
1365*ebfedea0SLionel Sambuc 			sum->hashed = seckey->checkhash = calloc(1, hashsize);
1366*ebfedea0SLionel Sambuc 		}
1367*ebfedea0SLionel Sambuc 		/* init the hash */
1368*ebfedea0SLionel Sambuc 		pgp_hash_any(&sum->hash, sum->hash_alg);
1369*ebfedea0SLionel Sambuc 		if (!sum->hash.init(&sum->hash)) {
1370*ebfedea0SLionel Sambuc 			(void) fprintf(stderr,
1371*ebfedea0SLionel Sambuc 				"pgp_push_checksum_writer: bad hash init\n");
1372*ebfedea0SLionel Sambuc 			/* just continue and die */
1373*ebfedea0SLionel Sambuc 			/* XXX - agc - no way to return failure */
1374*ebfedea0SLionel Sambuc 		}
1375*ebfedea0SLionel Sambuc 		pgp_writer_push(output, skey_checksum_writer,
1376*ebfedea0SLionel Sambuc 			skey_checksum_finaliser, skey_checksum_destroyer, sum);
1377*ebfedea0SLionel Sambuc 	}
1378*ebfedea0SLionel Sambuc }
1379*ebfedea0SLionel Sambuc 
1380*ebfedea0SLionel Sambuc /**************************************************************************/
1381*ebfedea0SLionel Sambuc 
1382*ebfedea0SLionel Sambuc #define MAX_PARTIAL_DATA_LENGTH 1073741824
1383*ebfedea0SLionel Sambuc 
1384*ebfedea0SLionel Sambuc typedef struct {
1385*ebfedea0SLionel Sambuc 	pgp_crypt_t	*crypt;
1386*ebfedea0SLionel Sambuc 	pgp_memory_t	*mem_data;
1387*ebfedea0SLionel Sambuc 	pgp_memory_t	*litmem;
1388*ebfedea0SLionel Sambuc 	pgp_output_t	*litoutput;
1389*ebfedea0SLionel Sambuc 	pgp_memory_t	*se_ip_mem;
1390*ebfedea0SLionel Sambuc 	pgp_output_t	*se_ip_out;
1391*ebfedea0SLionel Sambuc 	pgp_hash_t	 hash;
1392*ebfedea0SLionel Sambuc } str_enc_se_ip_t;
1393*ebfedea0SLionel Sambuc 
1394*ebfedea0SLionel Sambuc 
1395*ebfedea0SLionel Sambuc static unsigned
1396*ebfedea0SLionel Sambuc str_enc_se_ip_writer(const uint8_t *src,
1397*ebfedea0SLionel Sambuc 			    unsigned len,
1398*ebfedea0SLionel Sambuc 			    pgp_error_t **errors,
1399*ebfedea0SLionel Sambuc 			    pgp_writer_t *writer);
1400*ebfedea0SLionel Sambuc 
1401*ebfedea0SLionel Sambuc static unsigned
1402*ebfedea0SLionel Sambuc str_enc_se_ip_finaliser(pgp_error_t **errors,
1403*ebfedea0SLionel Sambuc 			       pgp_writer_t * writer);
1404*ebfedea0SLionel Sambuc 
1405*ebfedea0SLionel Sambuc static void     str_enc_se_ip_destroyer(pgp_writer_t *writer);
1406*ebfedea0SLionel Sambuc 
1407*ebfedea0SLionel Sambuc /* */
1408*ebfedea0SLionel Sambuc 
1409*ebfedea0SLionel Sambuc /**
1410*ebfedea0SLionel Sambuc \ingroup Core_WritersNext
1411*ebfedea0SLionel Sambuc \param output
1412*ebfedea0SLionel Sambuc \param pubkey
1413*ebfedea0SLionel Sambuc */
1414*ebfedea0SLionel Sambuc void
pgp_push_stream_enc_se_ip(pgp_output_t * output,const pgp_key_t * pubkey,const char * cipher)1415*ebfedea0SLionel Sambuc pgp_push_stream_enc_se_ip(pgp_output_t *output, const pgp_key_t *pubkey, const char *cipher)
1416*ebfedea0SLionel Sambuc {
1417*ebfedea0SLionel Sambuc 	pgp_pk_sesskey_t	*encrypted_pk_sesskey;
1418*ebfedea0SLionel Sambuc 	str_enc_se_ip_t		*se_ip;
1419*ebfedea0SLionel Sambuc 	const unsigned	 	 bufsz = 1024;
1420*ebfedea0SLionel Sambuc 	pgp_crypt_t		*encrypted;
1421*ebfedea0SLionel Sambuc 	uint8_t			*iv;
1422*ebfedea0SLionel Sambuc 
1423*ebfedea0SLionel Sambuc 	if ((se_ip = calloc(1, sizeof(*se_ip))) == NULL) {
1424*ebfedea0SLionel Sambuc 		(void) fprintf(stderr,
1425*ebfedea0SLionel Sambuc 			"pgp_push_stream_enc_se_ip: bad alloc\n");
1426*ebfedea0SLionel Sambuc 		return;
1427*ebfedea0SLionel Sambuc 	}
1428*ebfedea0SLionel Sambuc 	encrypted_pk_sesskey = pgp_create_pk_sesskey(pubkey, cipher);
1429*ebfedea0SLionel Sambuc 	pgp_write_pk_sesskey(output, encrypted_pk_sesskey);
1430*ebfedea0SLionel Sambuc 
1431*ebfedea0SLionel Sambuc 	/* Setup the se_ip */
1432*ebfedea0SLionel Sambuc 	if ((encrypted = calloc(1, sizeof(*encrypted))) == NULL) {
1433*ebfedea0SLionel Sambuc 		free(se_ip);
1434*ebfedea0SLionel Sambuc 		(void) fprintf(stderr,
1435*ebfedea0SLionel Sambuc 			"pgp_push_stream_enc_se_ip: bad alloc\n");
1436*ebfedea0SLionel Sambuc 		return;
1437*ebfedea0SLionel Sambuc 	}
1438*ebfedea0SLionel Sambuc 	pgp_crypt_any(encrypted, encrypted_pk_sesskey->symm_alg);
1439*ebfedea0SLionel Sambuc 	if ((iv = calloc(1, encrypted->blocksize)) == NULL) {
1440*ebfedea0SLionel Sambuc 		free(encrypted);
1441*ebfedea0SLionel Sambuc 		free(se_ip);
1442*ebfedea0SLionel Sambuc 		(void) fprintf(stderr,
1443*ebfedea0SLionel Sambuc 			"pgp_push_stream_enc_se_ip: bad alloc\n");
1444*ebfedea0SLionel Sambuc 		return;
1445*ebfedea0SLionel Sambuc 	}
1446*ebfedea0SLionel Sambuc 	encrypted->set_iv(encrypted, iv);
1447*ebfedea0SLionel Sambuc 	encrypted->set_crypt_key(encrypted, &encrypted_pk_sesskey->key[0]);
1448*ebfedea0SLionel Sambuc 	pgp_encrypt_init(encrypted);
1449*ebfedea0SLionel Sambuc 
1450*ebfedea0SLionel Sambuc 	se_ip->crypt = encrypted;
1451*ebfedea0SLionel Sambuc 
1452*ebfedea0SLionel Sambuc 	se_ip->mem_data = pgp_memory_new();
1453*ebfedea0SLionel Sambuc 	pgp_memory_init(se_ip->mem_data, bufsz);
1454*ebfedea0SLionel Sambuc 
1455*ebfedea0SLionel Sambuc 	se_ip->litmem = NULL;
1456*ebfedea0SLionel Sambuc 	se_ip->litoutput = NULL;
1457*ebfedea0SLionel Sambuc 
1458*ebfedea0SLionel Sambuc 	pgp_setup_memory_write(&se_ip->se_ip_out, &se_ip->se_ip_mem, bufsz);
1459*ebfedea0SLionel Sambuc 
1460*ebfedea0SLionel Sambuc 	/* And push writer on stack */
1461*ebfedea0SLionel Sambuc 	pgp_writer_push(output,
1462*ebfedea0SLionel Sambuc 			str_enc_se_ip_writer,
1463*ebfedea0SLionel Sambuc 			str_enc_se_ip_finaliser,
1464*ebfedea0SLionel Sambuc 			str_enc_se_ip_destroyer, se_ip);
1465*ebfedea0SLionel Sambuc 	/* tidy up */
1466*ebfedea0SLionel Sambuc 	free(encrypted_pk_sesskey);
1467*ebfedea0SLionel Sambuc 	free(iv);
1468*ebfedea0SLionel Sambuc }
1469*ebfedea0SLionel Sambuc 
1470*ebfedea0SLionel Sambuc 
1471*ebfedea0SLionel Sambuc /* calculate the partial data length */
1472*ebfedea0SLionel Sambuc static unsigned
partial_data_len(unsigned len)1473*ebfedea0SLionel Sambuc partial_data_len(unsigned len)
1474*ebfedea0SLionel Sambuc {
1475*ebfedea0SLionel Sambuc 	unsigned	mask;
1476*ebfedea0SLionel Sambuc 	int		i;
1477*ebfedea0SLionel Sambuc 
1478*ebfedea0SLionel Sambuc 	if (len == 0) {
1479*ebfedea0SLionel Sambuc 		(void) fprintf(stderr, "partial_data_len: 0 len\n");
1480*ebfedea0SLionel Sambuc 		return 0;
1481*ebfedea0SLionel Sambuc 	}
1482*ebfedea0SLionel Sambuc 	if (len > MAX_PARTIAL_DATA_LENGTH) {
1483*ebfedea0SLionel Sambuc 		return MAX_PARTIAL_DATA_LENGTH;
1484*ebfedea0SLionel Sambuc 	}
1485*ebfedea0SLionel Sambuc 	mask = MAX_PARTIAL_DATA_LENGTH;
1486*ebfedea0SLionel Sambuc 	for (i = 0; i <= 30; i++) {
1487*ebfedea0SLionel Sambuc 		if (mask & len) {
1488*ebfedea0SLionel Sambuc 			break;
1489*ebfedea0SLionel Sambuc 		}
1490*ebfedea0SLionel Sambuc 		mask >>= 1;
1491*ebfedea0SLionel Sambuc 	}
1492*ebfedea0SLionel Sambuc 	return mask;
1493*ebfedea0SLionel Sambuc }
1494*ebfedea0SLionel Sambuc 
1495*ebfedea0SLionel Sambuc static unsigned
write_partial_len(pgp_output_t * output,unsigned len)1496*ebfedea0SLionel Sambuc write_partial_len(pgp_output_t *output, unsigned len)
1497*ebfedea0SLionel Sambuc {
1498*ebfedea0SLionel Sambuc 	/* len must be a power of 2 from 0 to 30 */
1499*ebfedea0SLionel Sambuc 	uint8_t	c;
1500*ebfedea0SLionel Sambuc 	int	i;
1501*ebfedea0SLionel Sambuc 
1502*ebfedea0SLionel Sambuc 	for (i = 0; i <= 30; i++) {
1503*ebfedea0SLionel Sambuc 		if ((len >> i) & 1) {
1504*ebfedea0SLionel Sambuc 			break;
1505*ebfedea0SLionel Sambuc 		}
1506*ebfedea0SLionel Sambuc 	}
1507*ebfedea0SLionel Sambuc 	c = 224 + i;
1508*ebfedea0SLionel Sambuc 	return pgp_write(output, &c, 1);
1509*ebfedea0SLionel Sambuc }
1510*ebfedea0SLionel Sambuc 
1511*ebfedea0SLionel Sambuc static unsigned
stream_write_litdata(pgp_output_t * output,const uint8_t * data,unsigned len)1512*ebfedea0SLionel Sambuc stream_write_litdata(pgp_output_t *output,
1513*ebfedea0SLionel Sambuc 			const uint8_t *data,
1514*ebfedea0SLionel Sambuc 			unsigned len)
1515*ebfedea0SLionel Sambuc {
1516*ebfedea0SLionel Sambuc 	size_t          pdlen;
1517*ebfedea0SLionel Sambuc 
1518*ebfedea0SLionel Sambuc 	while (len > 0) {
1519*ebfedea0SLionel Sambuc 		pdlen = partial_data_len(len);
1520*ebfedea0SLionel Sambuc 		write_partial_len(output, (unsigned)pdlen);
1521*ebfedea0SLionel Sambuc 		pgp_write(output, data, (unsigned)pdlen);
1522*ebfedea0SLionel Sambuc 		data += pdlen;
1523*ebfedea0SLionel Sambuc 		len -= (unsigned)pdlen;
1524*ebfedea0SLionel Sambuc 	}
1525*ebfedea0SLionel Sambuc 	return 1;
1526*ebfedea0SLionel Sambuc }
1527*ebfedea0SLionel Sambuc 
1528*ebfedea0SLionel Sambuc static unsigned
stream_write_litdata_first(pgp_output_t * output,const uint8_t * data,unsigned len,const pgp_litdata_enum type)1529*ebfedea0SLionel Sambuc stream_write_litdata_first(pgp_output_t *output,
1530*ebfedea0SLionel Sambuc 				const uint8_t *data,
1531*ebfedea0SLionel Sambuc 				unsigned len,
1532*ebfedea0SLionel Sambuc 				const pgp_litdata_enum type)
1533*ebfedea0SLionel Sambuc {
1534*ebfedea0SLionel Sambuc 	/* \todo add filename  */
1535*ebfedea0SLionel Sambuc 	/* \todo add date */
1536*ebfedea0SLionel Sambuc 	/* \todo do we need to check text data for <cr><lf> line endings ? */
1537*ebfedea0SLionel Sambuc 
1538*ebfedea0SLionel Sambuc 	unsigned	sz_towrite;
1539*ebfedea0SLionel Sambuc 	size_t		sz_pd;
1540*ebfedea0SLionel Sambuc 
1541*ebfedea0SLionel Sambuc 	sz_towrite = 1 + 1 + 4 + len;
1542*ebfedea0SLionel Sambuc 	sz_pd = (size_t)partial_data_len(sz_towrite);
1543*ebfedea0SLionel Sambuc 	if (sz_pd < 512) {
1544*ebfedea0SLionel Sambuc 		(void) fprintf(stderr,
1545*ebfedea0SLionel Sambuc 			"stream_write_litdata_first: bad sz_pd\n");
1546*ebfedea0SLionel Sambuc 		return 0;
1547*ebfedea0SLionel Sambuc 	}
1548*ebfedea0SLionel Sambuc 	pgp_write_ptag(output, PGP_PTAG_CT_LITDATA);
1549*ebfedea0SLionel Sambuc 	write_partial_len(output, (unsigned)sz_pd);
1550*ebfedea0SLionel Sambuc 	pgp_write_scalar(output, (unsigned)type, 1);
1551*ebfedea0SLionel Sambuc 	pgp_write_scalar(output, 0, 1);
1552*ebfedea0SLionel Sambuc 	pgp_write_scalar(output, 0, 4);
1553*ebfedea0SLionel Sambuc 	pgp_write(output, data, (unsigned)(sz_pd - 6));
1554*ebfedea0SLionel Sambuc 
1555*ebfedea0SLionel Sambuc 	data += (sz_pd - 6);
1556*ebfedea0SLionel Sambuc 	sz_towrite -= (unsigned)sz_pd;
1557*ebfedea0SLionel Sambuc 
1558*ebfedea0SLionel Sambuc 	return stream_write_litdata(output, data, (unsigned)sz_towrite);
1559*ebfedea0SLionel Sambuc }
1560*ebfedea0SLionel Sambuc 
1561*ebfedea0SLionel Sambuc static unsigned
stream_write_litdata_last(pgp_output_t * output,const uint8_t * data,unsigned len)1562*ebfedea0SLionel Sambuc stream_write_litdata_last(pgp_output_t *output,
1563*ebfedea0SLionel Sambuc 				const uint8_t *data,
1564*ebfedea0SLionel Sambuc 				unsigned len)
1565*ebfedea0SLionel Sambuc {
1566*ebfedea0SLionel Sambuc 	pgp_write_length(output, len);
1567*ebfedea0SLionel Sambuc 	return pgp_write(output, data, len);
1568*ebfedea0SLionel Sambuc }
1569*ebfedea0SLionel Sambuc 
1570*ebfedea0SLionel Sambuc static unsigned
stream_write_se_ip(pgp_output_t * output,const uint8_t * data,unsigned len,str_enc_se_ip_t * se_ip)1571*ebfedea0SLionel Sambuc stream_write_se_ip(pgp_output_t *output,
1572*ebfedea0SLionel Sambuc 			const uint8_t *data,
1573*ebfedea0SLionel Sambuc 			unsigned len,
1574*ebfedea0SLionel Sambuc 			str_enc_se_ip_t *se_ip)
1575*ebfedea0SLionel Sambuc {
1576*ebfedea0SLionel Sambuc 	size_t          pdlen;
1577*ebfedea0SLionel Sambuc 
1578*ebfedea0SLionel Sambuc 	while (len > 0) {
1579*ebfedea0SLionel Sambuc 		pdlen = partial_data_len(len);
1580*ebfedea0SLionel Sambuc 		write_partial_len(output, (unsigned)pdlen);
1581*ebfedea0SLionel Sambuc 
1582*ebfedea0SLionel Sambuc 		pgp_push_enc_crypt(output, se_ip->crypt);
1583*ebfedea0SLionel Sambuc 		pgp_write(output, data, (unsigned)pdlen);
1584*ebfedea0SLionel Sambuc 		pgp_writer_pop(output);
1585*ebfedea0SLionel Sambuc 
1586*ebfedea0SLionel Sambuc 		se_ip->hash.add(&se_ip->hash, data, (unsigned)pdlen);
1587*ebfedea0SLionel Sambuc 
1588*ebfedea0SLionel Sambuc 		data += pdlen;
1589*ebfedea0SLionel Sambuc 		len -= (unsigned)pdlen;
1590*ebfedea0SLionel Sambuc 	}
1591*ebfedea0SLionel Sambuc 	return 1;
1592*ebfedea0SLionel Sambuc }
1593*ebfedea0SLionel Sambuc 
1594*ebfedea0SLionel Sambuc static unsigned
stream_write_se_ip_first(pgp_output_t * output,const uint8_t * data,unsigned len,str_enc_se_ip_t * se_ip)1595*ebfedea0SLionel Sambuc stream_write_se_ip_first(pgp_output_t *output,
1596*ebfedea0SLionel Sambuc 			const uint8_t *data,
1597*ebfedea0SLionel Sambuc 			unsigned len,
1598*ebfedea0SLionel Sambuc 			str_enc_se_ip_t *se_ip)
1599*ebfedea0SLionel Sambuc {
1600*ebfedea0SLionel Sambuc 	uint8_t	*preamble;
1601*ebfedea0SLionel Sambuc 	size_t	blocksize;
1602*ebfedea0SLionel Sambuc 	size_t 	preamblesize;
1603*ebfedea0SLionel Sambuc 	size_t 	sz_towrite;
1604*ebfedea0SLionel Sambuc 	size_t 	sz_pd;
1605*ebfedea0SLionel Sambuc 
1606*ebfedea0SLionel Sambuc 	blocksize = se_ip->crypt->blocksize;
1607*ebfedea0SLionel Sambuc 	preamblesize = blocksize + 2;
1608*ebfedea0SLionel Sambuc 	sz_towrite = preamblesize + 1 + len;
1609*ebfedea0SLionel Sambuc 	if ((preamble = calloc(1, preamblesize)) == NULL) {
1610*ebfedea0SLionel Sambuc 		(void) fprintf(stderr,
1611*ebfedea0SLionel Sambuc 			"stream_write_se_ip_first: bad alloc\n");
1612*ebfedea0SLionel Sambuc 		return 0;
1613*ebfedea0SLionel Sambuc 	}
1614*ebfedea0SLionel Sambuc 	sz_pd = (size_t)partial_data_len((unsigned)sz_towrite);
1615*ebfedea0SLionel Sambuc 	if (sz_pd < 512) {
1616*ebfedea0SLionel Sambuc 		free(preamble);
1617*ebfedea0SLionel Sambuc 		(void) fprintf(stderr,
1618*ebfedea0SLionel Sambuc 			"stream_write_se_ip_first: bad sz_pd\n");
1619*ebfedea0SLionel Sambuc 		return 0;
1620*ebfedea0SLionel Sambuc 	}
1621*ebfedea0SLionel Sambuc 	pgp_write_ptag(output, PGP_PTAG_CT_SE_IP_DATA);
1622*ebfedea0SLionel Sambuc 	write_partial_len(output, (unsigned)sz_pd);
1623*ebfedea0SLionel Sambuc 	pgp_write_scalar(output, PGP_SE_IP_DATA_VERSION, 1);
1624*ebfedea0SLionel Sambuc 	pgp_push_enc_crypt(output, se_ip->crypt);
1625*ebfedea0SLionel Sambuc 
1626*ebfedea0SLionel Sambuc 	pgp_random(preamble, blocksize);
1627*ebfedea0SLionel Sambuc 	preamble[blocksize] = preamble[blocksize - 2];
1628*ebfedea0SLionel Sambuc 	preamble[blocksize + 1] = preamble[blocksize - 1];
1629*ebfedea0SLionel Sambuc 	pgp_hash_any(&se_ip->hash, PGP_HASH_SHA1);
1630*ebfedea0SLionel Sambuc 	if (!se_ip->hash.init(&se_ip->hash)) {
1631*ebfedea0SLionel Sambuc 		free(preamble);
1632*ebfedea0SLionel Sambuc 		(void) fprintf(stderr,
1633*ebfedea0SLionel Sambuc 			"stream_write_se_ip_first: bad hash init\n");
1634*ebfedea0SLionel Sambuc 		return 0;
1635*ebfedea0SLionel Sambuc 	}
1636*ebfedea0SLionel Sambuc 	pgp_write(output, preamble, (unsigned)preamblesize);
1637*ebfedea0SLionel Sambuc 	se_ip->hash.add(&se_ip->hash, preamble, (unsigned)preamblesize);
1638*ebfedea0SLionel Sambuc 	pgp_write(output, data, (unsigned)(sz_pd - preamblesize - 1));
1639*ebfedea0SLionel Sambuc 	se_ip->hash.add(&se_ip->hash, data, (unsigned)(sz_pd - preamblesize - 1));
1640*ebfedea0SLionel Sambuc 	data += (sz_pd - preamblesize - 1);
1641*ebfedea0SLionel Sambuc 	sz_towrite -= sz_pd;
1642*ebfedea0SLionel Sambuc 	pgp_writer_pop(output);
1643*ebfedea0SLionel Sambuc 	stream_write_se_ip(output, data, (unsigned)sz_towrite, se_ip);
1644*ebfedea0SLionel Sambuc 	free(preamble);
1645*ebfedea0SLionel Sambuc 	return 1;
1646*ebfedea0SLionel Sambuc }
1647*ebfedea0SLionel Sambuc 
1648*ebfedea0SLionel Sambuc static unsigned
stream_write_se_ip_last(pgp_output_t * output,const uint8_t * data,unsigned len,str_enc_se_ip_t * se_ip)1649*ebfedea0SLionel Sambuc stream_write_se_ip_last(pgp_output_t *output,
1650*ebfedea0SLionel Sambuc 			const uint8_t *data,
1651*ebfedea0SLionel Sambuc 			unsigned len,
1652*ebfedea0SLionel Sambuc 			str_enc_se_ip_t *se_ip)
1653*ebfedea0SLionel Sambuc {
1654*ebfedea0SLionel Sambuc 	pgp_output_t	*mdcoutput;
1655*ebfedea0SLionel Sambuc 	pgp_memory_t	*mdcmem;
1656*ebfedea0SLionel Sambuc 	const size_t	 mdcsize = 1 + 1 + PGP_SHA1_HASH_SIZE;
1657*ebfedea0SLionel Sambuc 	uint8_t		 c;
1658*ebfedea0SLionel Sambuc 	uint8_t		 hashed[PGP_SHA1_HASH_SIZE];
1659*ebfedea0SLionel Sambuc 	size_t		 bufsize = len + mdcsize;
1660*ebfedea0SLionel Sambuc 
1661*ebfedea0SLionel Sambuc 	se_ip->hash.add(&se_ip->hash, data, len);
1662*ebfedea0SLionel Sambuc 
1663*ebfedea0SLionel Sambuc 	/* MDC packet tag */
1664*ebfedea0SLionel Sambuc 	c = MDC_PKT_TAG;
1665*ebfedea0SLionel Sambuc 	se_ip->hash.add(&se_ip->hash, &c, 1);
1666*ebfedea0SLionel Sambuc 
1667*ebfedea0SLionel Sambuc 	/* MDC packet len */
1668*ebfedea0SLionel Sambuc 	c = PGP_SHA1_HASH_SIZE;
1669*ebfedea0SLionel Sambuc 	se_ip->hash.add(&se_ip->hash, &c, 1);
1670*ebfedea0SLionel Sambuc 
1671*ebfedea0SLionel Sambuc 	/* finish */
1672*ebfedea0SLionel Sambuc 	se_ip->hash.finish(&se_ip->hash, hashed);
1673*ebfedea0SLionel Sambuc 
1674*ebfedea0SLionel Sambuc 	pgp_setup_memory_write(&mdcoutput, &mdcmem, mdcsize);
1675*ebfedea0SLionel Sambuc 	pgp_write_mdc(mdcoutput, hashed);
1676*ebfedea0SLionel Sambuc 
1677*ebfedea0SLionel Sambuc 	/* write length of last se_ip chunk */
1678*ebfedea0SLionel Sambuc 	pgp_write_length(output, (unsigned)bufsize);
1679*ebfedea0SLionel Sambuc 
1680*ebfedea0SLionel Sambuc 	/* encode everting */
1681*ebfedea0SLionel Sambuc 	pgp_push_enc_crypt(output, se_ip->crypt);
1682*ebfedea0SLionel Sambuc 
1683*ebfedea0SLionel Sambuc 	pgp_write(output, data, len);
1684*ebfedea0SLionel Sambuc 	pgp_write(output, pgp_mem_data(mdcmem), (unsigned)pgp_mem_len(mdcmem));
1685*ebfedea0SLionel Sambuc 
1686*ebfedea0SLionel Sambuc 	pgp_writer_pop(output);
1687*ebfedea0SLionel Sambuc 
1688*ebfedea0SLionel Sambuc 	pgp_teardown_memory_write(mdcoutput, mdcmem);
1689*ebfedea0SLionel Sambuc 
1690*ebfedea0SLionel Sambuc 	return 1;
1691*ebfedea0SLionel Sambuc }
1692*ebfedea0SLionel Sambuc 
1693*ebfedea0SLionel Sambuc static unsigned
str_enc_se_ip_writer(const uint8_t * src,unsigned len,pgp_error_t ** errors,pgp_writer_t * writer)1694*ebfedea0SLionel Sambuc str_enc_se_ip_writer(const uint8_t *src,
1695*ebfedea0SLionel Sambuc 			    unsigned len,
1696*ebfedea0SLionel Sambuc 			    pgp_error_t **errors,
1697*ebfedea0SLionel Sambuc 			    pgp_writer_t *writer)
1698*ebfedea0SLionel Sambuc {
1699*ebfedea0SLionel Sambuc 	str_enc_se_ip_t	*se_ip;
1700*ebfedea0SLionel Sambuc 	unsigned	 ret;
1701*ebfedea0SLionel Sambuc 	size_t           datalength;
1702*ebfedea0SLionel Sambuc 
1703*ebfedea0SLionel Sambuc 	se_ip = pgp_writer_get_arg(writer);
1704*ebfedea0SLionel Sambuc 	ret = 1;
1705*ebfedea0SLionel Sambuc 	if (se_ip->litoutput == NULL) {
1706*ebfedea0SLionel Sambuc 		/* first literal data chunk is not yet written */
1707*ebfedea0SLionel Sambuc 
1708*ebfedea0SLionel Sambuc 		pgp_memory_add(se_ip->mem_data, src, len);
1709*ebfedea0SLionel Sambuc 		datalength = pgp_mem_len(se_ip->mem_data);
1710*ebfedea0SLionel Sambuc 
1711*ebfedea0SLionel Sambuc 		/* 4.2.2.4. Partial Body Lengths */
1712*ebfedea0SLionel Sambuc 		/* The first partial length MUST be at least 512 octets long. */
1713*ebfedea0SLionel Sambuc 		if (datalength < 512) {
1714*ebfedea0SLionel Sambuc 			return 1;	/* will wait for more data or
1715*ebfedea0SLionel Sambuc 						 * end of stream             */
1716*ebfedea0SLionel Sambuc 		}
1717*ebfedea0SLionel Sambuc 		pgp_setup_memory_write(&se_ip->litoutput,
1718*ebfedea0SLionel Sambuc 				&se_ip->litmem, datalength + 32);
1719*ebfedea0SLionel Sambuc 		stream_write_litdata_first(se_ip->litoutput,
1720*ebfedea0SLionel Sambuc 				pgp_mem_data(se_ip->mem_data),
1721*ebfedea0SLionel Sambuc 				(unsigned)datalength,
1722*ebfedea0SLionel Sambuc 				PGP_LDT_BINARY);
1723*ebfedea0SLionel Sambuc 
1724*ebfedea0SLionel Sambuc 		stream_write_se_ip_first(se_ip->se_ip_out,
1725*ebfedea0SLionel Sambuc 				pgp_mem_data(se_ip->litmem),
1726*ebfedea0SLionel Sambuc 				(unsigned)pgp_mem_len(se_ip->litmem), se_ip);
1727*ebfedea0SLionel Sambuc 	} else {
1728*ebfedea0SLionel Sambuc 		stream_write_litdata(se_ip->litoutput, src, len);
1729*ebfedea0SLionel Sambuc 		stream_write_se_ip(se_ip->se_ip_out,
1730*ebfedea0SLionel Sambuc 				pgp_mem_data(se_ip->litmem),
1731*ebfedea0SLionel Sambuc 				(unsigned)pgp_mem_len(se_ip->litmem), se_ip);
1732*ebfedea0SLionel Sambuc 	}
1733*ebfedea0SLionel Sambuc 
1734*ebfedea0SLionel Sambuc 	/* now write memory to next writer */
1735*ebfedea0SLionel Sambuc 	ret = stacked_write(writer, pgp_mem_data(se_ip->se_ip_mem),
1736*ebfedea0SLionel Sambuc 				(unsigned)pgp_mem_len(se_ip->se_ip_mem), errors);
1737*ebfedea0SLionel Sambuc 
1738*ebfedea0SLionel Sambuc 	pgp_memory_clear(se_ip->litmem);
1739*ebfedea0SLionel Sambuc 	pgp_memory_clear(se_ip->se_ip_mem);
1740*ebfedea0SLionel Sambuc 
1741*ebfedea0SLionel Sambuc 	return ret;
1742*ebfedea0SLionel Sambuc }
1743*ebfedea0SLionel Sambuc 
1744*ebfedea0SLionel Sambuc /* write last chunk of data */
1745*ebfedea0SLionel Sambuc static unsigned
str_enc_se_ip_finaliser(pgp_error_t ** errors,pgp_writer_t * writer)1746*ebfedea0SLionel Sambuc str_enc_se_ip_finaliser(pgp_error_t **errors, pgp_writer_t *writer)
1747*ebfedea0SLionel Sambuc {
1748*ebfedea0SLionel Sambuc 	str_enc_se_ip_t	*se_ip;
1749*ebfedea0SLionel Sambuc 
1750*ebfedea0SLionel Sambuc 	se_ip = pgp_writer_get_arg(writer);
1751*ebfedea0SLionel Sambuc 	if (se_ip->litoutput == NULL) {
1752*ebfedea0SLionel Sambuc 		/* first literal data chunk was not written */
1753*ebfedea0SLionel Sambuc 		/* so we know the total length of data, write a simple packet */
1754*ebfedea0SLionel Sambuc 
1755*ebfedea0SLionel Sambuc 		/* create literal data packet from buffered data */
1756*ebfedea0SLionel Sambuc 		pgp_setup_memory_write(&se_ip->litoutput, &se_ip->litmem,
1757*ebfedea0SLionel Sambuc 				 pgp_mem_len(se_ip->mem_data) + 32);
1758*ebfedea0SLionel Sambuc 
1759*ebfedea0SLionel Sambuc 		pgp_write_litdata(se_ip->litoutput,
1760*ebfedea0SLionel Sambuc 			pgp_mem_data(se_ip->mem_data),
1761*ebfedea0SLionel Sambuc 			(const int)pgp_mem_len(se_ip->mem_data),
1762*ebfedea0SLionel Sambuc 			PGP_LDT_BINARY);
1763*ebfedea0SLionel Sambuc 
1764*ebfedea0SLionel Sambuc 		/* create SE IP packet set from this literal data */
1765*ebfedea0SLionel Sambuc 		pgp_write_se_ip_pktset(se_ip->se_ip_out,
1766*ebfedea0SLionel Sambuc 				pgp_mem_data(se_ip->litmem),
1767*ebfedea0SLionel Sambuc 				(unsigned)pgp_mem_len(se_ip->litmem),
1768*ebfedea0SLionel Sambuc 				se_ip->crypt);
1769*ebfedea0SLionel Sambuc 
1770*ebfedea0SLionel Sambuc 	} else {
1771*ebfedea0SLionel Sambuc 		/* finish writing */
1772*ebfedea0SLionel Sambuc 		stream_write_litdata_last(se_ip->litoutput, NULL, 0);
1773*ebfedea0SLionel Sambuc 		stream_write_se_ip_last(se_ip->se_ip_out,
1774*ebfedea0SLionel Sambuc 				pgp_mem_data(se_ip->litmem),
1775*ebfedea0SLionel Sambuc 				(unsigned)pgp_mem_len(se_ip->litmem), se_ip);
1776*ebfedea0SLionel Sambuc 	}
1777*ebfedea0SLionel Sambuc 
1778*ebfedea0SLionel Sambuc 	/* now write memory to next writer */
1779*ebfedea0SLionel Sambuc 	return stacked_write(writer, pgp_mem_data(se_ip->se_ip_mem),
1780*ebfedea0SLionel Sambuc 				 (unsigned)pgp_mem_len(se_ip->se_ip_mem), errors);
1781*ebfedea0SLionel Sambuc }
1782*ebfedea0SLionel Sambuc 
1783*ebfedea0SLionel Sambuc static void
str_enc_se_ip_destroyer(pgp_writer_t * writer)1784*ebfedea0SLionel Sambuc str_enc_se_ip_destroyer(pgp_writer_t *writer)
1785*ebfedea0SLionel Sambuc {
1786*ebfedea0SLionel Sambuc 	str_enc_se_ip_t *se_ip;
1787*ebfedea0SLionel Sambuc 
1788*ebfedea0SLionel Sambuc 	se_ip = pgp_writer_get_arg(writer);
1789*ebfedea0SLionel Sambuc 	pgp_memory_free(se_ip->mem_data);
1790*ebfedea0SLionel Sambuc 	pgp_teardown_memory_write(se_ip->litoutput, se_ip->litmem);
1791*ebfedea0SLionel Sambuc 	pgp_teardown_memory_write(se_ip->se_ip_out, se_ip->se_ip_mem);
1792*ebfedea0SLionel Sambuc 
1793*ebfedea0SLionel Sambuc 	se_ip->crypt->decrypt_finish(se_ip->crypt);
1794*ebfedea0SLionel Sambuc 
1795*ebfedea0SLionel Sambuc 	free(se_ip->crypt);
1796*ebfedea0SLionel Sambuc 	free(se_ip);
1797*ebfedea0SLionel Sambuc }
1798