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