xref: /netbsd-src/crypto/external/bsd/netpgp/dist/src/lib/crypto.c (revision 62a8debe1dc62962e18a1c918def78666141273b)
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.21 2010/03/05 16:01:09 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\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 uint8_t *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 	uint8_t   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 
223 	if (__ops_get_debug_level(__FILE__)) {
224 		printf("write_parsed_cb: ");
225 		__ops_print_packet(&cbinfo->printstate, pkt);
226 	}
227 	if (pkt->tag != OPS_PTAG_CT_UNARMOURED_TEXT && cbinfo->printstate.skipping) {
228 		puts("...end of skip");
229 		cbinfo->printstate.skipping = 0;
230 	}
231 	switch (pkt->tag) {
232 	case OPS_PTAG_CT_UNARMOURED_TEXT:
233 		printf("OPS_PTAG_CT_UNARMOURED_TEXT\n");
234 		if (!cbinfo->printstate.skipping) {
235 			puts("Skipping...");
236 			cbinfo->printstate.skipping = 1;
237 		}
238 		fwrite(content->unarmoured_text.data, 1,
239 		       content->unarmoured_text.length, stdout);
240 		break;
241 
242 	case OPS_PTAG_CT_PK_SESSION_KEY:
243 		return pk_sesskey_cb(pkt, cbinfo);
244 
245 	case OPS_GET_SECKEY:
246 		return get_seckey_cb(pkt, cbinfo);
247 
248 	case OPS_GET_PASSPHRASE:
249 		return cbinfo->cryptinfo.getpassphrase(pkt, cbinfo);
250 
251 	case OPS_PTAG_CT_LITDATA_BODY:
252 		return litdata_cb(pkt, cbinfo);
253 
254 	case OPS_PTAG_CT_ARMOUR_HEADER:
255 	case OPS_PTAG_CT_ARMOUR_TRAILER:
256 	case OPS_PTAG_CT_ENCRYPTED_PK_SESSION_KEY:
257 	case OPS_PTAG_CT_COMPRESSED:
258 	case OPS_PTAG_CT_LITDATA_HEADER:
259 	case OPS_PTAG_CT_SE_IP_DATA_BODY:
260 	case OPS_PTAG_CT_SE_IP_DATA_HEADER:
261 	case OPS_PTAG_CT_SE_DATA_BODY:
262 	case OPS_PTAG_CT_SE_DATA_HEADER:
263 		/* Ignore these packets  */
264 		/* They're handled in __ops_parse_packet() */
265 		/* and nothing else needs to be done */
266 		break;
267 
268 	default:
269 		if (__ops_get_debug_level(__FILE__)) {
270 			fprintf(stderr, "Unexpected packet tag=%d (0x%x)\n",
271 				pkt->tag,
272 				pkt->tag);
273 		}
274 		break;
275 	}
276 
277 	return OPS_RELEASE_MEMORY;
278 }
279 
280 /**
281 \ingroup HighLevel_Crypto
282 Encrypt a file
283 \param infile Name of file to be encrypted
284 \param outfile Name of file to write to. If NULL, name is constructed from infile
285 \param pubkey Public Key to encrypt file for
286 \param use_armour Write armoured text, if set
287 \param allow_overwrite Allow output file to be overwrwritten if it exists
288 \return 1 if OK; else 0
289 */
290 unsigned
291 __ops_encrypt_file(__ops_io_t *io,
292 			const char *infile,
293 			const char *outfile,
294 			const __ops_key_t *pubkey,
295 			const unsigned use_armour,
296 			const unsigned allow_overwrite)
297 {
298 	__ops_output_t	*output;
299 	__ops_memory_t	*inmem;
300 	int		 fd_out;
301 
302 	__OPS_USED(io);
303 	inmem = __ops_memory_new();
304 	if (!__ops_mem_readfile(inmem, infile)) {
305 		return 0;
306 	}
307 	fd_out = __ops_setup_file_write(&output, outfile, allow_overwrite);
308 	if (fd_out < 0) {
309 		__ops_memory_free(inmem);
310 		return 0;
311 	}
312 
313 	/* set armoured/not armoured here */
314 	if (use_armour) {
315 		__ops_writer_push_armor_msg(output);
316 	}
317 
318 	/* Push the encrypted writer */
319 	__ops_push_enc_se_ip(output, pubkey);
320 
321 	/* This does the writing */
322 	__ops_write(output, __ops_mem_data(inmem), __ops_mem_len(inmem));
323 
324 	/* tidy up */
325 	__ops_memory_free(inmem);
326 	__ops_teardown_file_write(output, fd_out);
327 
328 	return 1;
329 }
330 
331 /* encrypt the contents of the input buffer, and return the mem structure */
332 __ops_memory_t *
333 __ops_encrypt_buf(__ops_io_t *io,
334 			const void *input,
335 			const size_t insize,
336 			const __ops_key_t *pubkey,
337 			const unsigned use_armour)
338 {
339 	__ops_output_t	*output;
340 	__ops_memory_t	*outmem;
341 
342 	__OPS_USED(io);
343 	if (input == NULL) {
344 		(void) fprintf(io->errs,
345 			"__ops_encrypt_buf: null memory\n");
346 		return 0;
347 	}
348 
349 	__ops_setup_memory_write(&output, &outmem, insize);
350 
351 	/* set armoured/not armoured here */
352 	if (use_armour) {
353 		__ops_writer_push_armor_msg(output);
354 	}
355 
356 	/* Push the encrypted writer */
357 	__ops_push_enc_se_ip(output, pubkey);
358 
359 	/* This does the writing */
360 	__ops_write(output, input, insize);
361 
362 	/* tidy up */
363 	__ops_writer_close(output);
364 	__ops_output_delete(output);
365 
366 	return outmem;
367 }
368 
369 /**
370    \ingroup HighLevel_Crypto
371    \brief Decrypt a file.
372    \param infile Name of file to be decrypted
373    \param outfile Name of file to write to. If NULL, the filename is constructed from the input filename, following GPG conventions.
374    \param keyring Keyring to use
375    \param use_armour Expect armoured text, if set
376    \param allow_overwrite Allow output file to overwritten, if set.
377    \param getpassfunc Callback to use to get passphrase
378 */
379 
380 unsigned
381 __ops_decrypt_file(__ops_io_t *io,
382 			const char *infile,
383 			const char *outfile,
384 			__ops_keyring_t *secring,
385 			__ops_keyring_t *pubring,
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.secring = secring;
448 	parse->cbinfo.passfp = passfp;
449 	parse->cbinfo.cryptinfo.getpassphrase = getpassfunc;
450 	parse->cbinfo.cryptinfo.pubring = pubring;
451 
452 	/* Set up armour/passphrase options */
453 	if (use_armour) {
454 		__ops_reader_push_dearmour(parse);
455 	}
456 
457 	/* Do it */
458 	__ops_parse(parse, printerrors);
459 
460 	/* Unsetup */
461 	if (use_armour) {
462 		__ops_reader_pop_dearmour(parse);
463 	}
464 
465 	if (filename) {
466 		__ops_teardown_file_write(parse->cbinfo.output, fd_out);
467 		free(filename);
468 	}
469 	__ops_teardown_file_read(parse, fd_in);
470 	/* \todo cleardown crypt */
471 
472 	return 1;
473 }
474 
475 /* decrypt an area of memory */
476 __ops_memory_t *
477 __ops_decrypt_buf(__ops_io_t *io,
478 			const void *input,
479 			const size_t insize,
480 			__ops_keyring_t *secring,
481 			__ops_keyring_t *pubring,
482 			const unsigned use_armour,
483 			void *passfp,
484 			__ops_cbfunc_t *getpassfunc)
485 {
486 	__ops_stream_t	*parse = NULL;
487 	__ops_memory_t	*outmem;
488 	__ops_memory_t	*inmem;
489 	const int	 printerrors = 1;
490 
491 	if (input == NULL) {
492 		(void) fprintf(io->errs,
493 			"__ops_encrypt_buf: null memory\n");
494 		return 0;
495 	}
496 
497 	inmem = __ops_memory_new();
498 	__ops_memory_add(inmem, input, insize);
499 
500 	/* set up to read from memory */
501 	__ops_setup_memory_read(io, &parse, inmem,
502 				    NULL,
503 				    write_parsed_cb,
504 				    0);
505 
506 	/* setup for writing decrypted contents to given output file */
507 	__ops_setup_memory_write(&parse->cbinfo.output, &outmem, insize);
508 
509 	/* setup keyring and passphrase callback */
510 	parse->cbinfo.cryptinfo.secring = secring;
511 	parse->cbinfo.cryptinfo.pubring = pubring;
512 	parse->cbinfo.passfp = passfp;
513 	parse->cbinfo.cryptinfo.getpassphrase = getpassfunc;
514 
515 	/* Set up armour/passphrase options */
516 	if (use_armour) {
517 		__ops_reader_push_dearmour(parse);
518 	}
519 
520 	/* Do it */
521 	__ops_parse(parse, printerrors);
522 
523 	/* Unsetup */
524 	if (use_armour) {
525 		__ops_reader_pop_dearmour(parse);
526 	}
527 
528 	/* tidy up */
529 	__ops_teardown_memory_read(parse, inmem);
530 	__ops_memory_release(inmem);
531 	free(inmem);
532 
533 	__ops_writer_close(parse->cbinfo.output);
534 	__ops_output_delete(parse->cbinfo.output);
535 
536 	return outmem;
537 }
538 
539