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