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