xref: /netbsd-src/crypto/external/bsd/netpgp/dist/src/lib/crypto.c (revision 5c46dd73a9bcb28b2994504ea090f64066b17a77)
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.23 2010/05/16 02:46:25 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(uint8_t *buf,
88 				unsigned buflen,
89 				const BIGNUM *encmpi,
90 				const __ops_seckey_t *seckey)
91 {
92 	uint8_t   encmpibuf[NETPGP_BUFSIZ];
93 	uint8_t   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\nencrypted data     : ");
113 		hexdump(stderr, encmpibuf, 16, " ");
114 		(void) fprintf(stderr, "\n");
115 	}
116 	n = __ops_rsa_private_decrypt(mpibuf, encmpibuf,
117 				(unsigned)(BN_num_bits(encmpi) + 7) / 8,
118 				&seckey->key.rsa, &seckey->pubkey.key.rsa);
119 	if (n == -1) {
120 		(void) fprintf(stderr, "ops_rsa_private_decrypt failure\n");
121 		return -1;
122 	}
123 
124 	if (__ops_get_debug_level(__FILE__)) {
125 		(void) fprintf(stderr, "decrypted encoded m buf     : ");
126 		hexdump(stderr, mpibuf, 16, " ");
127 		(void) fprintf(stderr, "\n");
128 	}
129 	if (n <= 0) {
130 		return -1;
131 	}
132 
133 	if (__ops_get_debug_level(__FILE__)) {
134 		fprintf(stderr, " decrypted=%d ", n);
135 		hexdump(stderr, mpibuf, (unsigned)n, "");
136 		fprintf(stderr, "\n");
137 	}
138 	/* Decode EME-PKCS1_V1_5 (RFC 2437). */
139 
140 	if (mpibuf[0] != 0 || mpibuf[1] != 2) {
141 		return -1;
142 	}
143 
144 	/* Skip the random bytes. */
145 	for (i = 2; i < n && mpibuf[i]; ++i) {
146 	}
147 
148 	if (i == n || i < 10) {
149 		return -1;
150 	}
151 
152 	/* Skip the zero */
153 	i += 1;
154 
155 	/* this is the unencoded m buf */
156 	if ((unsigned) (n - i) <= buflen) {
157 		(void) memcpy(buf, mpibuf + i, (unsigned)(n - i)); /* XXX - Flexelint */
158 	}
159 
160 	if (__ops_get_debug_level(__FILE__)) {
161 		fprintf(stderr, "decoded m buf:\n");
162 		hexdump(stderr, buf, (size_t)(n - i), " ");
163 		fprintf(stderr, "\n");
164 	}
165 	return n - i;
166 }
167 
168 /**
169 \ingroup Core_MPI
170 \brief RSA-encrypt an MPI
171 */
172 unsigned
173 __ops_rsa_encrypt_mpi(const uint8_t *encoded_m_buf,
174 		    const size_t sz_encoded_m_buf,
175 		    const __ops_pubkey_t * pubkey,
176 		    __ops_pk_sesskey_params_t * skp)
177 {
178 
179 	uint8_t   encmpibuf[NETPGP_BUFSIZ];
180 	int             n;
181 
182 	if (sz_encoded_m_buf != (size_t)BN_num_bytes(pubkey->key.rsa.n)) {
183 		(void) fprintf(stderr, "sz_encoded_m_buf wrong\n");
184 		return 0;
185 	}
186 
187 	n = __ops_rsa_public_encrypt(encmpibuf, encoded_m_buf,
188 				sz_encoded_m_buf, &pubkey->key.rsa);
189 	if (n == -1) {
190 		(void) fprintf(stderr, "__ops_rsa_public_encrypt failure\n");
191 		return 0;
192 	}
193 
194 	if (n <= 0)
195 		return 0;
196 
197 	skp->rsa.encrypted_m = BN_bin2bn(encmpibuf, n, NULL);
198 
199 	if (__ops_get_debug_level(__FILE__)) {
200 		(void) fprintf(stderr, "encrypted mpi buf     : ");
201 		hexdump(stderr, encmpibuf, 16, " ");
202 		(void) fprintf(stderr, "\n");
203 	}
204 	return 1;
205 }
206 
207 static __ops_cb_ret_t
208 write_parsed_cb(const __ops_packet_t *pkt, __ops_cbdata_t *cbinfo)
209 {
210 	const __ops_contents_t	*content = &pkt->u;
211 
212 	if (__ops_get_debug_level(__FILE__)) {
213 		printf("write_parsed_cb: ");
214 		__ops_print_packet(&cbinfo->printstate, pkt);
215 	}
216 	if (pkt->tag != OPS_PTAG_CT_UNARMOURED_TEXT && cbinfo->printstate.skipping) {
217 		puts("...end of skip");
218 		cbinfo->printstate.skipping = 0;
219 	}
220 	switch (pkt->tag) {
221 	case OPS_PTAG_CT_UNARMOURED_TEXT:
222 		printf("OPS_PTAG_CT_UNARMOURED_TEXT\n");
223 		if (!cbinfo->printstate.skipping) {
224 			puts("Skipping...");
225 			cbinfo->printstate.skipping = 1;
226 		}
227 		fwrite(content->unarmoured_text.data, 1,
228 		       content->unarmoured_text.length, stdout);
229 		break;
230 
231 	case OPS_PTAG_CT_PK_SESSION_KEY:
232 		return pk_sesskey_cb(pkt, cbinfo);
233 
234 	case OPS_GET_SECKEY:
235 		return get_seckey_cb(pkt, cbinfo);
236 
237 	case OPS_GET_PASSPHRASE:
238 		return cbinfo->cryptinfo.getpassphrase(pkt, cbinfo);
239 
240 	case OPS_PTAG_CT_LITDATA_BODY:
241 		return litdata_cb(pkt, cbinfo);
242 
243 	case OPS_PTAG_CT_ARMOUR_HEADER:
244 	case OPS_PTAG_CT_ARMOUR_TRAILER:
245 	case OPS_PTAG_CT_ENCRYPTED_PK_SESSION_KEY:
246 	case OPS_PTAG_CT_COMPRESSED:
247 	case OPS_PTAG_CT_LITDATA_HEADER:
248 	case OPS_PTAG_CT_SE_IP_DATA_BODY:
249 	case OPS_PTAG_CT_SE_IP_DATA_HEADER:
250 	case OPS_PTAG_CT_SE_DATA_BODY:
251 	case OPS_PTAG_CT_SE_DATA_HEADER:
252 		/* Ignore these packets  */
253 		/* They're handled in __ops_parse_packet() */
254 		/* and nothing else needs to be done */
255 		break;
256 
257 	default:
258 		if (__ops_get_debug_level(__FILE__)) {
259 			fprintf(stderr, "Unexpected packet tag=%d (0x%x)\n",
260 				pkt->tag,
261 				pkt->tag);
262 		}
263 		break;
264 	}
265 
266 	return OPS_RELEASE_MEMORY;
267 }
268 
269 /**
270 \ingroup HighLevel_Crypto
271 Encrypt a file
272 \param infile Name of file to be encrypted
273 \param outfile Name of file to write to. If NULL, name is constructed from infile
274 \param pubkey Public Key to encrypt file for
275 \param use_armour Write armoured text, if set
276 \param allow_overwrite Allow output file to be overwrwritten if it exists
277 \return 1 if OK; else 0
278 */
279 unsigned
280 __ops_encrypt_file(__ops_io_t *io,
281 			const char *infile,
282 			const char *outfile,
283 			const __ops_key_t *pubkey,
284 			const unsigned use_armour,
285 			const unsigned allow_overwrite)
286 {
287 	__ops_output_t	*output;
288 	__ops_memory_t	*inmem;
289 	int		 fd_out;
290 
291 	__OPS_USED(io);
292 	inmem = __ops_memory_new();
293 	if (!__ops_mem_readfile(inmem, infile)) {
294 		return 0;
295 	}
296 	fd_out = __ops_setup_file_write(&output, outfile, allow_overwrite);
297 	if (fd_out < 0) {
298 		__ops_memory_free(inmem);
299 		return 0;
300 	}
301 
302 	/* set armoured/not armoured here */
303 	if (use_armour) {
304 		__ops_writer_push_armor_msg(output);
305 	}
306 
307 	/* Push the encrypted writer */
308 	__ops_push_enc_se_ip(output, pubkey);
309 
310 	/* This does the writing */
311 	__ops_write(output, __ops_mem_data(inmem), __ops_mem_len(inmem));
312 
313 	/* tidy up */
314 	__ops_memory_free(inmem);
315 	__ops_teardown_file_write(output, fd_out);
316 
317 	return 1;
318 }
319 
320 /* encrypt the contents of the input buffer, and return the mem structure */
321 __ops_memory_t *
322 __ops_encrypt_buf(__ops_io_t *io,
323 			const void *input,
324 			const size_t insize,
325 			const __ops_key_t *pubkey,
326 			const unsigned use_armour)
327 {
328 	__ops_output_t	*output;
329 	__ops_memory_t	*outmem;
330 
331 	__OPS_USED(io);
332 	if (input == NULL) {
333 		(void) fprintf(io->errs,
334 			"__ops_encrypt_buf: null memory\n");
335 		return 0;
336 	}
337 
338 	__ops_setup_memory_write(&output, &outmem, insize);
339 
340 	/* set armoured/not armoured here */
341 	if (use_armour) {
342 		__ops_writer_push_armor_msg(output);
343 	}
344 
345 	/* Push the encrypted writer */
346 	__ops_push_enc_se_ip(output, pubkey);
347 
348 	/* This does the writing */
349 	__ops_write(output, input, insize);
350 
351 	/* tidy up */
352 	__ops_writer_close(output);
353 	__ops_output_delete(output);
354 
355 	return outmem;
356 }
357 
358 /**
359    \ingroup HighLevel_Crypto
360    \brief Decrypt a file.
361    \param infile Name of file to be decrypted
362    \param outfile Name of file to write to. If NULL, the filename is constructed from the input filename, following GPG conventions.
363    \param keyring Keyring to use
364    \param use_armour Expect armoured text, if set
365    \param allow_overwrite Allow output file to overwritten, if set.
366    \param getpassfunc Callback to use to get passphrase
367 */
368 
369 unsigned
370 __ops_decrypt_file(__ops_io_t *io,
371 			const char *infile,
372 			const char *outfile,
373 			__ops_keyring_t *secring,
374 			__ops_keyring_t *pubring,
375 			const unsigned use_armour,
376 			const unsigned allow_overwrite,
377 			void *passfp,
378 			__ops_cbfunc_t *getpassfunc)
379 {
380 	__ops_stream_t	*parse = NULL;
381 	const int		 printerrors = 1;
382 	char			*filename = NULL;
383 	int			 fd_in;
384 	int			 fd_out;
385 
386 	/* setup for reading from given input file */
387 	fd_in = __ops_setup_file_read(io, &parse, infile,
388 				    NULL,
389 				    write_parsed_cb,
390 				    0);
391 	if (fd_in < 0) {
392 		perror(infile);
393 		return 0;
394 	}
395 	/* setup output filename */
396 	if (outfile) {
397 		fd_out = __ops_setup_file_write(&parse->cbinfo.output, outfile,
398 				allow_overwrite);
399 		if (fd_out < 0) {
400 			perror(outfile);
401 			__ops_teardown_file_read(parse, fd_in);
402 			return 0;
403 		}
404 	} else {
405 		const int	suffixlen = 4;
406 		const char     *suffix = infile + strlen(infile) - suffixlen;
407 		unsigned	filenamelen;
408 
409 		if (strcmp(suffix, ".gpg") == 0 ||
410 		    strcmp(suffix, ".asc") == 0) {
411 			filenamelen = strlen(infile) - strlen(suffix);
412 			if ((filename = calloc(1, filenamelen + 1)) == NULL) {
413 				(void) fprintf(stderr, "can't allocate %" PRIsize "d bytes\n",
414 					(size_t)(filenamelen + 1));
415 				return 0;
416 			}
417 			(void) strncpy(filename, infile, filenamelen);
418 			filename[filenamelen] = 0x0;
419 		}
420 
421 		fd_out = __ops_setup_file_write(&parse->cbinfo.output,
422 					filename, allow_overwrite);
423 		if (fd_out < 0) {
424 			perror(filename);
425 			free(filename);
426 			__ops_teardown_file_read(parse, fd_in);
427 			return 0;
428 		}
429 	}
430 
431 	/* \todo check for suffix matching armour param */
432 
433 	/* setup for writing decrypted contents to given output file */
434 
435 	/* setup keyring and passphrase callback */
436 	parse->cbinfo.cryptinfo.secring = secring;
437 	parse->cbinfo.passfp = passfp;
438 	parse->cbinfo.cryptinfo.getpassphrase = getpassfunc;
439 	parse->cbinfo.cryptinfo.pubring = pubring;
440 
441 	/* Set up armour/passphrase options */
442 	if (use_armour) {
443 		__ops_reader_push_dearmour(parse);
444 	}
445 
446 	/* Do it */
447 	__ops_parse(parse, printerrors);
448 
449 	/* Unsetup */
450 	if (use_armour) {
451 		__ops_reader_pop_dearmour(parse);
452 	}
453 
454 	if (filename) {
455 		__ops_teardown_file_write(parse->cbinfo.output, fd_out);
456 		free(filename);
457 	}
458 	__ops_teardown_file_read(parse, fd_in);
459 	/* \todo cleardown crypt */
460 
461 	return 1;
462 }
463 
464 /* decrypt an area of memory */
465 __ops_memory_t *
466 __ops_decrypt_buf(__ops_io_t *io,
467 			const void *input,
468 			const size_t insize,
469 			__ops_keyring_t *secring,
470 			__ops_keyring_t *pubring,
471 			const unsigned use_armour,
472 			void *passfp,
473 			__ops_cbfunc_t *getpassfunc)
474 {
475 	__ops_stream_t	*parse = NULL;
476 	__ops_memory_t	*outmem;
477 	__ops_memory_t	*inmem;
478 	const int	 printerrors = 1;
479 
480 	if (input == NULL) {
481 		(void) fprintf(io->errs,
482 			"__ops_encrypt_buf: null memory\n");
483 		return 0;
484 	}
485 
486 	inmem = __ops_memory_new();
487 	__ops_memory_add(inmem, input, insize);
488 
489 	/* set up to read from memory */
490 	__ops_setup_memory_read(io, &parse, inmem,
491 				    NULL,
492 				    write_parsed_cb,
493 				    0);
494 
495 	/* setup for writing decrypted contents to given output file */
496 	__ops_setup_memory_write(&parse->cbinfo.output, &outmem, insize);
497 
498 	/* setup keyring and passphrase callback */
499 	parse->cbinfo.cryptinfo.secring = secring;
500 	parse->cbinfo.cryptinfo.pubring = pubring;
501 	parse->cbinfo.passfp = passfp;
502 	parse->cbinfo.cryptinfo.getpassphrase = getpassfunc;
503 
504 	/* Set up armour/passphrase options */
505 	if (use_armour) {
506 		__ops_reader_push_dearmour(parse);
507 	}
508 
509 	/* Do it */
510 	__ops_parse(parse, printerrors);
511 
512 	/* Unsetup */
513 	if (use_armour) {
514 		__ops_reader_pop_dearmour(parse);
515 	}
516 
517 	/* tidy up */
518 	__ops_teardown_memory_read(parse, inmem);
519 	__ops_memory_release(inmem);
520 	free(inmem);
521 
522 	__ops_writer_close(parse->cbinfo.output);
523 	__ops_output_delete(parse->cbinfo.output);
524 
525 	return outmem;
526 }
527 
528