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