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