xref: /netbsd-src/crypto/external/bsd/netpgp/dist/src/lib/crypto.c (revision 3816d47b2c42fcd6e549e3407f842a5b1a1d23ad)
1 /*-
2  * Copyright (c) 2009 The NetBSD Foundation, Inc.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to The NetBSD Foundation
6  * by Alistair Crooks (agc@NetBSD.org)
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 /*
30  * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
31  * All rights reserved.
32  * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
33  * their moral rights under the UK Copyright Design and Patents Act 1988 to
34  * be recorded as the authors of this copyright work.
35  *
36  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
37  * use this file except in compliance with the License.
38  *
39  * You may obtain a copy of the License at
40  *     http://www.apache.org/licenses/LICENSE-2.0
41  *
42  * Unless required by applicable law or agreed to in writing, software
43  * distributed under the License is distributed on an "AS IS" BASIS,
44  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
45  *
46  * See the License for the specific language governing permissions and
47  * limitations under the License.
48  */
49 #include "config.h"
50 
51 #ifdef HAVE_SYS_CDEFS_H
52 #include <sys/cdefs.h>
53 #endif
54 
55 #if defined(__NetBSD__)
56 __COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved.");
57 __RCSID("$NetBSD: crypto.c,v 1.18 2009/12/22 06:03:24 agc Exp $");
58 #endif
59 
60 #include <sys/types.h>
61 #include <sys/stat.h>
62 
63 #ifdef HAVE_UNISTD_H
64 #include <unistd.h>
65 #endif
66 
67 #include <string.h>
68 
69 #include "types.h"
70 #include "crypto.h"
71 #include "readerwriter.h"
72 #include "memory.h"
73 #include "netpgpdefs.h"
74 #include "signature.h"
75 
76 /**
77 \ingroup Core_MPI
78 \brief Decrypt and unencode MPI
79 \param buf Buffer in which to write decrypted unencoded MPI
80 \param buflen Length of buffer
81 \param encmpi
82 \param seckey
83 \return length of MPI
84 \note only RSA at present
85 */
86 int
87 __ops_decrypt_decode_mpi(unsigned char *buf,
88 				unsigned buflen,
89 				const BIGNUM *encmpi,
90 				const __ops_seckey_t *seckey)
91 {
92 	unsigned char   encmpibuf[NETPGP_BUFSIZ];
93 	unsigned char   mpibuf[NETPGP_BUFSIZ];
94 	unsigned        mpisize;
95 	int             n;
96 	int             i;
97 
98 	mpisize = (unsigned)BN_num_bytes(encmpi);
99 	/* MPI can't be more than 65,536 */
100 	if (mpisize > sizeof(encmpibuf)) {
101 		(void) fprintf(stderr, "mpisize too big %u\n", mpisize);
102 		return -1;
103 	}
104 	BN_bn2bin(encmpi, encmpibuf);
105 
106 	if (seckey->pubkey.alg != OPS_PKA_RSA) {
107 		(void) fprintf(stderr, "pubkey algorithm wrong\n");
108 		return -1;
109 	}
110 
111 	if (__ops_get_debug_level(__FILE__)) {
112 		(void) fprintf(stderr, "\nDECRYPTING\n");
113 		(void) fprintf(stderr, "encrypted data     : ");
114 		for (i = 0; i < 16; i++) {
115 			(void) fprintf(stderr, "%2x ", encmpibuf[i]);
116 		}
117 		(void) fprintf(stderr, "\n");
118 	}
119 	n = __ops_rsa_private_decrypt(mpibuf, encmpibuf,
120 				(unsigned)(BN_num_bits(encmpi) + 7) / 8,
121 				&seckey->key.rsa, &seckey->pubkey.key.rsa);
122 	if (n == -1) {
123 		(void) fprintf(stderr, "ops_rsa_private_decrypt failure\n");
124 		return -1;
125 	}
126 
127 	if (__ops_get_debug_level(__FILE__)) {
128 		(void) fprintf(stderr, "decrypted encoded m buf     : ");
129 		for (i = 0; i < 16; i++) {
130 			(void) fprintf(stderr, "%2x ", mpibuf[i]);
131 		}
132 		(void) fprintf(stderr, "\n");
133 	}
134 	if (n <= 0) {
135 		return -1;
136 	}
137 
138 	if (__ops_get_debug_level(__FILE__)) {
139 		printf(" decrypted=%d ", n);
140 		hexdump(stdout, mpibuf, (unsigned)n, "");
141 		printf("\n");
142 	}
143 	/* Decode EME-PKCS1_V1_5 (RFC 2437). */
144 
145 	if (mpibuf[0] != 0 || mpibuf[1] != 2) {
146 		return -1;
147 	}
148 
149 	/* Skip the random bytes. */
150 	for (i = 2; i < n && mpibuf[i]; ++i) {
151 	}
152 
153 	if (i == n || i < 10) {
154 		return -1;
155 	}
156 
157 	/* Skip the zero */
158 	i += 1;
159 
160 	/* this is the unencoded m buf */
161 	if ((unsigned) (n - i) <= buflen) {
162 		(void) memcpy(buf, mpibuf + i, (unsigned)(n - i)); /* XXX - Flexelint */
163 	}
164 
165 	if (__ops_get_debug_level(__FILE__)) {
166 		int             j;
167 
168 		printf("decoded m buf:\n");
169 		for (j = 0; j < n - i; j++)
170 			printf("%2x ", buf[j]);
171 		printf("\n");
172 	}
173 	return n - i;
174 }
175 
176 /**
177 \ingroup Core_MPI
178 \brief RSA-encrypt an MPI
179 */
180 unsigned
181 __ops_rsa_encrypt_mpi(const unsigned char *encoded_m_buf,
182 		    const size_t sz_encoded_m_buf,
183 		    const __ops_pubkey_t * pubkey,
184 		    __ops_pk_sesskey_params_t * skp)
185 {
186 
187 	unsigned char   encmpibuf[NETPGP_BUFSIZ];
188 	int             n;
189 
190 	if (sz_encoded_m_buf != (size_t)BN_num_bytes(pubkey->key.rsa.n)) {
191 		(void) fprintf(stderr, "sz_encoded_m_buf wrong\n");
192 		return 0;
193 	}
194 
195 	n = __ops_rsa_public_encrypt(encmpibuf, encoded_m_buf,
196 				sz_encoded_m_buf, &pubkey->key.rsa);
197 	if (n == -1) {
198 		(void) fprintf(stderr, "__ops_rsa_public_encrypt failure\n");
199 		return 0;
200 	}
201 
202 	if (n <= 0)
203 		return 0;
204 
205 	skp->rsa.encrypted_m = BN_bin2bn(encmpibuf, n, NULL);
206 
207 	if (__ops_get_debug_level(__FILE__)) {
208 		int             i;
209 		(void) fprintf(stderr, "encrypted mpi buf     : ");
210 		for (i = 0; i < 16; i++) {
211 			(void) fprintf(stderr, "%2x ", encmpibuf[i]);
212 		}
213 		(void) fprintf(stderr, "\n");
214 	}
215 	return 1;
216 }
217 
218 static __ops_cb_ret_t
219 write_parsed_cb(const __ops_packet_t *pkt, __ops_cbdata_t *cbinfo)
220 {
221 	const __ops_contents_t	*content = &pkt->u;
222 	static unsigned		 skipping;	/* XXX - put skipping into pkt? */
223 
224 	if (__ops_get_debug_level(__FILE__)) {
225 		printf("write_parsed_cb: ");
226 		__ops_print_packet(pkt);
227 	}
228 	if (pkt->tag != OPS_PTAG_CT_UNARMOURED_TEXT && skipping) {
229 		puts("...end of skip");
230 		skipping = 0;
231 	}
232 	switch (pkt->tag) {
233 	case OPS_PTAG_CT_UNARMOURED_TEXT:
234 		printf("OPS_PTAG_CT_UNARMOURED_TEXT\n");
235 		if (!skipping) {
236 			puts("Skipping...");
237 			skipping = 1;
238 		}
239 		fwrite(content->unarmoured_text.data, 1,
240 		       content->unarmoured_text.length, stdout);
241 		break;
242 
243 	case OPS_PTAG_CT_PK_SESSION_KEY:
244 		return pk_sesskey_cb(pkt, cbinfo);
245 
246 	case OPS_GET_SECKEY:
247 		return get_seckey_cb(pkt, cbinfo);
248 
249 	case OPS_GET_PASSPHRASE:
250 		return cbinfo->cryptinfo.getpassphrase(pkt, cbinfo);
251 
252 	case OPS_PTAG_CT_LITDATA_BODY:
253 		return litdata_cb(pkt, cbinfo);
254 
255 	case OPS_PTAG_CT_ARMOUR_HEADER:
256 	case OPS_PTAG_CT_ARMOUR_TRAILER:
257 	case OPS_PTAG_CT_ENCRYPTED_PK_SESSION_KEY:
258 	case OPS_PTAG_CT_COMPRESSED:
259 	case OPS_PTAG_CT_LITDATA_HEADER:
260 	case OPS_PTAG_CT_SE_IP_DATA_BODY:
261 	case OPS_PTAG_CT_SE_IP_DATA_HEADER:
262 	case OPS_PTAG_CT_SE_DATA_BODY:
263 	case OPS_PTAG_CT_SE_DATA_HEADER:
264 		/* Ignore these packets  */
265 		/* They're handled in __ops_parse_packet() */
266 		/* and nothing else needs to be done */
267 		break;
268 
269 	default:
270 		if (__ops_get_debug_level(__FILE__)) {
271 			fprintf(stderr, "Unexpected packet tag=%d (0x%x)\n",
272 				pkt->tag,
273 				pkt->tag);
274 		}
275 		break;
276 	}
277 
278 	return OPS_RELEASE_MEMORY;
279 }
280 
281 /**
282 \ingroup HighLevel_Crypto
283 Encrypt a file
284 \param infile Name of file to be encrypted
285 \param outfile Name of file to write to. If NULL, name is constructed from infile
286 \param pubkey Public Key to encrypt file for
287 \param use_armour Write armoured text, if set
288 \param allow_overwrite Allow output file to be overwrwritten if it exists
289 \return 1 if OK; else 0
290 */
291 unsigned
292 __ops_encrypt_file(__ops_io_t *io,
293 			const char *infile,
294 			const char *outfile,
295 			const __ops_key_t *pubkey,
296 			const unsigned use_armour,
297 			const unsigned allow_overwrite)
298 {
299 	__ops_output_t	*output;
300 	__ops_memory_t	*inmem;
301 	int		 fd_out;
302 
303 	__OPS_USED(io);
304 	inmem = __ops_memory_new();
305 	if (!__ops_mem_readfile(inmem, infile)) {
306 		return 0;
307 	}
308 	fd_out = __ops_setup_file_write(&output, outfile, allow_overwrite);
309 	if (fd_out < 0) {
310 		__ops_memory_free(inmem);
311 		return 0;
312 	}
313 
314 	/* set armoured/not armoured here */
315 	if (use_armour) {
316 		__ops_writer_push_armor_msg(output);
317 	}
318 
319 	/* Push the encrypted writer */
320 	__ops_push_enc_se_ip(output, pubkey);
321 
322 	/* This does the writing */
323 	__ops_write(output, __ops_mem_data(inmem), __ops_mem_len(inmem));
324 
325 	/* tidy up */
326 	__ops_memory_free(inmem);
327 	__ops_teardown_file_write(output, fd_out);
328 
329 	return 1;
330 }
331 
332 /* encrypt the contents of the input buffer, and return the mem structure */
333 __ops_memory_t *
334 __ops_encrypt_buf(__ops_io_t *io,
335 			const void *input,
336 			const size_t insize,
337 			const __ops_key_t *pubkey,
338 			const unsigned use_armour)
339 {
340 	__ops_output_t	*output;
341 	__ops_memory_t	*outmem;
342 
343 	__OPS_USED(io);
344 	if (input == NULL) {
345 		(void) fprintf(io->errs,
346 			"__ops_encrypt_buf: null memory\n");
347 		return 0;
348 	}
349 
350 	__ops_setup_memory_write(&output, &outmem, insize);
351 
352 	/* set armoured/not armoured here */
353 	if (use_armour) {
354 		__ops_writer_push_armor_msg(output);
355 	}
356 
357 	/* Push the encrypted writer */
358 	__ops_push_enc_se_ip(output, pubkey);
359 
360 	/* This does the writing */
361 	__ops_write(output, input, insize);
362 
363 	/* tidy up */
364 	__ops_writer_close(output);
365 	__ops_output_delete(output);
366 
367 	return outmem;
368 }
369 
370 /**
371    \ingroup HighLevel_Crypto
372    \brief Decrypt a file.
373    \param infile Name of file to be decrypted
374    \param outfile Name of file to write to. If NULL, the filename is constructed from the input filename, following GPG conventions.
375    \param keyring Keyring to use
376    \param use_armour Expect armoured text, if set
377    \param allow_overwrite Allow output file to overwritten, if set.
378    \param getpassfunc Callback to use to get passphrase
379 */
380 
381 unsigned
382 __ops_decrypt_file(__ops_io_t *io,
383 			const char *infile,
384 			const char *outfile,
385 			__ops_keyring_t *keyring,
386 			const unsigned use_armour,
387 			const unsigned allow_overwrite,
388 			void *passfp,
389 			__ops_cbfunc_t *getpassfunc)
390 {
391 	__ops_stream_t	*parse = NULL;
392 	const int		 printerrors = 1;
393 	char			*filename = NULL;
394 	int			 fd_in;
395 	int			 fd_out;
396 
397 	/* setup for reading from given input file */
398 	fd_in = __ops_setup_file_read(io, &parse, infile,
399 				    NULL,
400 				    write_parsed_cb,
401 				    0);
402 	if (fd_in < 0) {
403 		perror(infile);
404 		return 0;
405 	}
406 	/* setup output filename */
407 	if (outfile) {
408 		fd_out = __ops_setup_file_write(&parse->cbinfo.output, outfile,
409 				allow_overwrite);
410 		if (fd_out < 0) {
411 			perror(outfile);
412 			__ops_teardown_file_read(parse, fd_in);
413 			return 0;
414 		}
415 	} else {
416 		const int	suffixlen = 4;
417 		const char     *suffix = infile + strlen(infile) - suffixlen;
418 		unsigned	filenamelen;
419 
420 		if (strcmp(suffix, ".gpg") == 0 ||
421 		    strcmp(suffix, ".asc") == 0) {
422 			filenamelen = strlen(infile) - strlen(suffix);
423 			if ((filename = calloc(1, filenamelen + 1)) == NULL) {
424 				(void) fprintf(stderr, "can't allocate %" PRIsize "d bytes\n",
425 					(size_t)(filenamelen + 1));
426 				return 0;
427 			}
428 			(void) strncpy(filename, infile, filenamelen);
429 			filename[filenamelen] = 0x0;
430 		}
431 
432 		fd_out = __ops_setup_file_write(&parse->cbinfo.output,
433 					filename, allow_overwrite);
434 		if (fd_out < 0) {
435 			perror(filename);
436 			free(filename);
437 			__ops_teardown_file_read(parse, fd_in);
438 			return 0;
439 		}
440 	}
441 
442 	/* \todo check for suffix matching armour param */
443 
444 	/* setup for writing decrypted contents to given output file */
445 
446 	/* setup keyring and passphrase callback */
447 	parse->cbinfo.cryptinfo.keyring = keyring;
448 	parse->cbinfo.passfp = passfp;
449 	parse->cbinfo.cryptinfo.getpassphrase = getpassfunc;
450 
451 	/* Set up armour/passphrase options */
452 	if (use_armour) {
453 		__ops_reader_push_dearmour(parse);
454 	}
455 
456 	/* Do it */
457 	__ops_parse(parse, printerrors);
458 
459 	/* Unsetup */
460 	if (use_armour) {
461 		__ops_reader_pop_dearmour(parse);
462 	}
463 
464 	if (filename) {
465 		__ops_teardown_file_write(parse->cbinfo.output, fd_out);
466 		free(filename);
467 	}
468 	__ops_teardown_file_read(parse, fd_in);
469 	/* \todo cleardown crypt */
470 
471 	return 1;
472 }
473 
474 /* decrypt an area of memory */
475 __ops_memory_t *
476 __ops_decrypt_buf(__ops_io_t *io,
477 			const void *input,
478 			const size_t insize,
479 			__ops_keyring_t *keyring,
480 			const unsigned use_armour,
481 			void *passfp,
482 			__ops_cbfunc_t *getpassfunc)
483 {
484 	__ops_stream_t	*parse = NULL;
485 	__ops_memory_t	*outmem;
486 	__ops_memory_t	*inmem;
487 	const int	 printerrors = 1;
488 
489 	if (input == NULL) {
490 		(void) fprintf(io->errs,
491 			"__ops_encrypt_buf: null memory\n");
492 		return 0;
493 	}
494 
495 	inmem = __ops_memory_new();
496 	__ops_memory_add(inmem, input, insize);
497 
498 	/* set up to read from memory */
499 	__ops_setup_memory_read(io, &parse, inmem,
500 				    NULL,
501 				    write_parsed_cb,
502 				    0);
503 
504 	/* setup for writing decrypted contents to given output file */
505 	__ops_setup_memory_write(&parse->cbinfo.output, &outmem, insize);
506 
507 	/* setup keyring and passphrase callback */
508 	parse->cbinfo.cryptinfo.keyring = keyring;
509 	parse->cbinfo.passfp = passfp;
510 	parse->cbinfo.cryptinfo.getpassphrase = getpassfunc;
511 
512 	/* Set up armour/passphrase options */
513 	if (use_armour) {
514 		__ops_reader_push_dearmour(parse);
515 	}
516 
517 	/* Do it */
518 	__ops_parse(parse, printerrors);
519 
520 	/* Unsetup */
521 	if (use_armour) {
522 		__ops_reader_pop_dearmour(parse);
523 	}
524 
525 	/* tidy up */
526 	__ops_teardown_memory_read(parse, inmem);
527 	__ops_memory_release(inmem);
528 	free(inmem);
529 
530 	__ops_writer_close(parse->cbinfo.output);
531 	__ops_output_delete(parse->cbinfo.output);
532 
533 	return outmem;
534 }
535 
536