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