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_FCNTL_H 52 #include <fcntl.h> 53 #endif 54 55 #ifdef HAVE_UNISTD_H 56 #include <unistd.h> 57 #endif 58 59 #include <string.h> 60 61 #include "crypto.h" 62 #include "readerwriter.h" 63 #include "memory.h" 64 #include "parse_local.h" 65 #include "netpgpdefs.h" 66 #include "signature.h" 67 68 /** 69 \ingroup Core_MPI 70 \brief Decrypt and unencode MPI 71 \param buf Buffer in which to write decrypted unencoded MPI 72 \param buflen Length of buffer 73 \param encmpi 74 \param seckey 75 \return length of MPI 76 \note only RSA at present 77 */ 78 int 79 __ops_decrypt_and_unencode_mpi(unsigned char *buf, 80 unsigned buflen, 81 const BIGNUM * encmpi, 82 const __ops_seckey_t *seckey) 83 { 84 unsigned char encmpibuf[NETPGP_BUFSIZ]; 85 unsigned char mpibuf[NETPGP_BUFSIZ]; 86 unsigned mpisize; 87 int n; 88 int i; 89 90 mpisize = BN_num_bytes(encmpi); 91 /* MPI can't be more than 65,536 */ 92 if (mpisize > sizeof(encmpibuf)) { 93 (void) fprintf(stderr, "mpisize too big %u\n", mpisize); 94 return -1; 95 } 96 BN_bn2bin(encmpi, encmpibuf); 97 98 if (seckey->pubkey.alg != OPS_PKA_RSA) { 99 (void) fprintf(stderr, "pubkey algorithm wrong\n"); 100 return -1; 101 } 102 103 if (__ops_get_debug_level(__FILE__)) { 104 (void) fprintf(stderr, "\nDECRYPTING\n"); 105 (void) fprintf(stderr, "encrypted data : "); 106 for (i = 0; i < 16; i++) { 107 (void) fprintf(stderr, "%2x ", encmpibuf[i]); 108 } 109 (void) fprintf(stderr, "\n"); 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 119 if (__ops_get_debug_level(__FILE__)) { 120 (void) fprintf(stderr, "decrypted encoded m buf : "); 121 for (i = 0; i < 16; i++) { 122 (void) fprintf(stderr, "%2x ", mpibuf[i]); 123 } 124 (void) fprintf(stderr, "\n"); 125 } 126 if (n <= 0) { 127 return -1; 128 } 129 130 if (__ops_get_debug_level(__FILE__)) { 131 printf(" decrypted=%d ", n); 132 hexdump(mpibuf, (unsigned)n, ""); 133 printf("\n"); 134 } 135 /* Decode EME-PKCS1_V1_5 (RFC 2437). */ 136 137 if (mpibuf[0] != 0 || mpibuf[1] != 2) { 138 return -1; 139 } 140 141 /* Skip the random bytes. */ 142 for (i = 2; i < n && mpibuf[i]; ++i) { 143 } 144 145 if (i == n || i < 10) { 146 return -1; 147 } 148 149 /* Skip the zero */ 150 ++i; 151 152 /* this is the unencoded m buf */ 153 if ((unsigned) (n - i) <= buflen) { 154 (void) memcpy(buf, mpibuf + i, (unsigned)(n - i)); 155 } 156 157 if (__ops_get_debug_level(__FILE__)) { 158 int j; 159 160 printf("decoded m buf:\n"); 161 for (j = 0; j < n - i; j++) 162 printf("%2x ", buf[j]); 163 printf("\n"); 164 } 165 return n - i; 166 } 167 168 /** 169 \ingroup Core_MPI 170 \brief RSA-encrypt an MPI 171 */ 172 bool 173 __ops_rsa_encrypt_mpi(const unsigned char *encoded_m_buf, 174 const size_t sz_encoded_m_buf, 175 const __ops_pubkey_t * pubkey, 176 __ops_pk_sesskey_parameters_t * skp) 177 { 178 179 unsigned char encmpibuf[NETPGP_BUFSIZ]; 180 int n = 0; 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 false; 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 false; 192 } 193 194 if (n <= 0) 195 return false; 196 197 skp->rsa.encrypted_m = BN_bin2bn(encmpibuf, n, NULL); 198 199 if (__ops_get_debug_level(__FILE__)) { 200 int i; 201 fprintf(stderr, "encrypted mpi buf : "); 202 for (i = 0; i < 16; i++) { 203 fprintf(stderr, "%2x ", encmpibuf[i]); 204 } 205 fprintf(stderr, "\n"); 206 } 207 return true; 208 } 209 210 static __ops_parse_cb_return_t 211 callback_write_parsed(const __ops_packet_t *, __ops_callback_data_t *); 212 213 /** 214 \ingroup HighLevel_Crypto 215 Encrypt a file 216 \param infile Name of file to be encrypted 217 \param outfile Name of file to write to. If NULL, name is constructed from infile 218 \param pub_key Public Key to encrypt file for 219 \param use_armour Write armoured text, if set 220 \param allow_overwrite Allow output file to be overwrwritten if it exists 221 \return true if OK; else false 222 */ 223 bool 224 __ops_encrypt_file(const char *infile, 225 const char *outfile, 226 const __ops_keydata_t * pub_key, 227 const bool use_armour, 228 const bool allow_overwrite) 229 { 230 __ops_createinfo_t *create; 231 unsigned char *buf; 232 size_t bufsz; 233 size_t done; 234 int fd_in = 0; 235 int fd_out = 0; 236 237 #ifdef O_BINARY 238 fd_in = open(infile, O_RDONLY | O_BINARY); 239 #else 240 fd_in = open(infile, O_RDONLY); 241 #endif 242 if (fd_in < 0) { 243 perror(infile); 244 return false; 245 } 246 fd_out = __ops_setup_file_write(&create, outfile, allow_overwrite); 247 if (fd_out < 0) { 248 return false; 249 } 250 251 /* set armoured/not armoured here */ 252 if (use_armour) { 253 __ops_writer_push_armoured_message(create); 254 } 255 256 /* Push the encrypted writer */ 257 __ops_writer_push_encrypt_se_ip(create, pub_key); 258 259 /* Do the writing */ 260 261 buf = NULL; 262 bufsz = 16; 263 done = 0; 264 for (;;) { 265 int n = 0; 266 267 buf = realloc(buf, done + bufsz); 268 269 if ((n = read(fd_in, buf + done, bufsz)) == 0) { 270 break; 271 } 272 if (n < 0) { 273 (void) fprintf(stderr, "Problem in read\n"); 274 return false; 275 } 276 done += n; 277 } 278 279 /* This does the writing */ 280 __ops_write(buf, done, create); 281 282 /* tidy up */ 283 close(fd_in); 284 free(buf); 285 __ops_teardown_file_write(create, fd_out); 286 287 return true; 288 } 289 290 /** 291 \ingroup HighLevel_Crypto 292 \brief Decrypt a file. 293 \param infile Name of file to be decrypted 294 \param outfile Name of file to write to. If NULL, the filename is constructed from the input filename, following GPG conventions. 295 \param keyring Keyring to use 296 \param use_armour Expect armoured text, if set 297 \param allow_overwrite Allow output file to overwritten, if set. 298 \param cb_get_passphrase Callback to use to get passphrase 299 */ 300 301 bool 302 __ops_decrypt_file(const char *infile, 303 const char *outfile, 304 __ops_keyring_t *keyring, 305 const bool use_armour, 306 const bool allow_overwrite, 307 __ops_parse_cb_t *cb_get_passphrase) 308 { 309 __ops_parseinfo_t *parse = NULL; 310 char *filename = NULL; 311 int fd_in = 0; 312 int fd_out = 0; 313 314 /* setup for reading from given input file */ 315 fd_in = __ops_setup_file_read(&parse, infile, 316 NULL, 317 callback_write_parsed, 318 false); 319 if (fd_in < 0) { 320 perror(infile); 321 return false; 322 } 323 324 /* setup output filename */ 325 if (outfile) { 326 fd_out = __ops_setup_file_write(&parse->cbinfo.cinfo, outfile, 327 allow_overwrite); 328 if (fd_out < 0) { 329 perror(outfile); 330 __ops_teardown_file_read(parse, fd_in); 331 return false; 332 } 333 } else { 334 unsigned filenamelen; 335 int suffixlen = 4; 336 const char *suffix = infile + strlen(infile) - suffixlen; 337 338 if (strcmp(suffix, ".gpg") == 0 || 339 strcmp(suffix, ".asc") == 0) { 340 filenamelen = strlen(infile) - strlen(suffix); 341 filename = calloc(1, filenamelen + 1); 342 (void) strncpy(filename, infile, filenamelen); 343 filename[filenamelen] = 0x0; 344 } 345 346 fd_out = __ops_setup_file_write(&parse->cbinfo.cinfo, 347 filename, allow_overwrite); 348 if (fd_out < 0) { 349 perror(filename); 350 (void) free(filename); 351 __ops_teardown_file_read(parse, fd_in); 352 return false; 353 } 354 if (filename) { 355 (void) free(filename); 356 } 357 } 358 359 /* \todo check for suffix matching armour param */ 360 361 /* setup for writing decrypted contents to given output file */ 362 363 /* setup keyring and passphrase callback */ 364 parse->cbinfo.cryptinfo.keyring = keyring; 365 parse->cbinfo.cryptinfo.cb_get_passphrase = cb_get_passphrase; 366 367 /* Set up armour/passphrase options */ 368 if (use_armour) { 369 __ops_reader_push_dearmour(parse); 370 } 371 372 /* Do it */ 373 __ops_parse(parse, 1); 374 375 /* Unsetup */ 376 if (use_armour) { 377 __ops_reader_pop_dearmour(parse); 378 } 379 380 if (filename) { 381 __ops_teardown_file_write(parse->cbinfo.cinfo, fd_out); 382 } 383 __ops_teardown_file_read(parse, fd_in); 384 /* \todo cleardown crypt */ 385 386 return true; 387 } 388 389 static __ops_parse_cb_return_t 390 callback_write_parsed(const __ops_packet_t *pkt, __ops_callback_data_t *cbinfo) 391 { 392 const __ops_parser_content_union_t *content = &pkt->u; 393 static bool skipping; 394 395 if (__ops_get_debug_level(__FILE__)) { 396 printf("callback_write_parsed: "); 397 __ops_print_packet(pkt); 398 } 399 if (pkt->tag != OPS_PTAG_CT_UNARMOURED_TEXT && skipping) { 400 puts("...end of skip"); 401 skipping = false; 402 } 403 switch (pkt->tag) { 404 case OPS_PTAG_CT_UNARMOURED_TEXT: 405 printf("OPS_PTAG_CT_UNARMOURED_TEXT\n"); 406 if (!skipping) { 407 puts("Skipping..."); 408 skipping = true; 409 } 410 fwrite(content->unarmoured_text.data, 1, 411 content->unarmoured_text.length, stdout); 412 break; 413 414 case OPS_PTAG_CT_PK_SESSION_KEY: 415 return pk_sesskey_cb(pkt, cbinfo); 416 417 case OPS_PARSER_CMD_GET_SECRET_KEY: 418 return get_seckey_cb(pkt, cbinfo); 419 420 case OPS_PARSER_CMD_GET_SK_PASSPHRASE: 421 return cbinfo->cryptinfo.cb_get_passphrase(pkt, cbinfo); 422 423 case OPS_PTAG_CT_LITERAL_DATA_BODY: 424 return litdata_cb(pkt, cbinfo); 425 426 case OPS_PTAG_CT_ARMOUR_HEADER: 427 case OPS_PTAG_CT_ARMOUR_TRAILER: 428 case OPS_PTAG_CT_ENCRYPTED_PK_SESSION_KEY: 429 case OPS_PTAG_CT_COMPRESSED: 430 case OPS_PTAG_CT_LITERAL_DATA_HEADER: 431 case OPS_PTAG_CT_SE_IP_DATA_BODY: 432 case OPS_PTAG_CT_SE_IP_DATA_HEADER: 433 case OPS_PTAG_CT_SE_DATA_BODY: 434 case OPS_PTAG_CT_SE_DATA_HEADER: 435 /* Ignore these packets */ 436 /* They're handled in __ops_parse_packet() */ 437 /* and nothing else needs to be done */ 438 break; 439 440 default: 441 if (__ops_get_debug_level(__FILE__)) { 442 fprintf(stderr, "Unexpected packet tag=%d (0x%x)\n", 443 pkt->tag, 444 pkt->tag); 445 } 446 break; 447 } 448 449 return OPS_RELEASE_MEMORY; 450 } 451