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