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