| Commit | Line | Data |
|---|---|---|
| 62efe6ec MD |
1 | /* |
| 2 | * Copyright (c) 2011-2012 The DragonFly Project. All rights reserved. | |
| 3 | * | |
| 4 | * This code is derived from software contributed to The DragonFly Project | |
| 5 | * by Matthew Dillon <dillon@dragonflybsd.org> | |
| 6 | * by Venkatesh Srinivas <vsrinivas@dragonflybsd.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 | * | |
| 12 | * 1. Redistributions of source code must retain the above copyright | |
| 13 | * notice, this list of conditions and the following disclaimer. | |
| 14 | * 2. Redistributions in binary form must reproduce the above copyright | |
| 15 | * notice, this list of conditions and the following disclaimer in | |
| 16 | * the documentation and/or other materials provided with the | |
| 17 | * distribution. | |
| 18 | * 3. Neither the name of The DragonFly Project nor the names of its | |
| 19 | * contributors may be used to endorse or promote products derived | |
| 20 | * from this software without specific, prior written permission. | |
| 21 | * | |
| 22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 23 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| 25 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| 26 | * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| 27 | * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| 28 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
| 29 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| 30 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
| 31 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
| 32 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 33 | * SUCH DAMAGE. | |
| 34 | */ | |
| 35 | ||
| 36 | #include "hammer2.h" | |
| 37 | ||
| 62efe6ec | 38 | /* |
| 02454b3e MD |
39 | * Setup crypto for pthreads |
| 40 | */ | |
| 41 | static pthread_mutex_t *crypto_locks; | |
| 42 | int crypto_count; | |
| 43 | ||
| 44 | static | |
| 45 | unsigned long | |
| 46 | hammer2_crypto_id_callback(void) | |
| 47 | { | |
| 48 | return ((unsigned long)(uintptr_t)pthread_self()); | |
| 49 | } | |
| 50 | ||
| 51 | static | |
| 52 | void | |
| 53 | hammer2_crypto_locking_callback(int mode, int type, | |
| 54 | const char *file __unused, int line __unused) | |
| 55 | { | |
| 56 | assert(type >= 0 && type < crypto_count); | |
| 57 | if (mode & CRYPTO_LOCK) { | |
| 58 | pthread_mutex_lock(&crypto_locks[type]); | |
| 59 | } else { | |
| 60 | pthread_mutex_unlock(&crypto_locks[type]); | |
| 61 | } | |
| 62 | } | |
| 63 | ||
| 64 | void | |
| 65 | hammer2_crypto_setup(void) | |
| 66 | { | |
| 67 | crypto_count = CRYPTO_num_locks(); | |
| 68 | crypto_locks = calloc(crypto_count, sizeof(crypto_locks[0])); | |
| 69 | CRYPTO_set_id_callback(hammer2_crypto_id_callback); | |
| 70 | CRYPTO_set_locking_callback(hammer2_crypto_locking_callback); | |
| 71 | } | |
| 72 | ||
| 73 | /* | |
| 62efe6ec MD |
74 | * Synchronously negotiate crypto for a new session. This must occur |
| 75 | * within 10 seconds or the connection is error'd out. | |
| 76 | * | |
| 77 | * We work off the IP address and/or reverse DNS. The IP address is | |
| 78 | * checked first, followed by the IP address at various levels of granularity, | |
| 79 | * followed by the full domain name and domain names at various levels of | |
| 80 | * granularity. | |
| 81 | * | |
| 82 | * /etc/hammer2/remote/<name>.pub - Contains a public key | |
| 83 | * /etc/hammer2/remote/<name>.none - Indicates no encryption (empty file) | |
| 84 | * (e.g. localhost.none). | |
| 85 | * | |
| 86 | * We first attempt to locate a public key file based on the peer address or | |
| 87 | * peer FQDN. | |
| 88 | * | |
| 89 | * <name>.none - No further negotiation is needed. We simply return. | |
| 90 | * All communication proceeds without encryption. | |
| 91 | * No public key handshake occurs in this situation. | |
| 92 | * (both ends must match). | |
| 93 | * | |
| 94 | * <name>.pub - We have located the public key for the peer. Both | |
| 95 | * sides transmit a block encrypted with their private | |
| 96 | * keys and the peer's public key. | |
| 97 | * | |
| 98 | * Both sides receive a block and decrypt it. | |
| 99 | * | |
| 100 | * Both sides formulate a reply using the decrypted | |
| 101 | * block and transmit it. | |
| 102 | * | |
| 103 | * communication proceeds with the negotiated session | |
| 104 | * key (typically AES-256-CBC). | |
| 105 | * | |
| 106 | * If we fail to locate the appropriate file and no floating.db exists the | |
| 107 | * connection is terminated without further action. | |
| 108 | * | |
| 109 | * If floating.db exists the connection proceeds with a floating negotiation. | |
| 110 | */ | |
| 111 | typedef union { | |
| 112 | struct sockaddr sa; | |
| 113 | struct sockaddr_in sa_in; | |
| 114 | struct sockaddr_in6 sa_in6; | |
| 115 | } sockaddr_any_t; | |
| 116 | ||
| 117 | void | |
| 118 | hammer2_crypto_negotiate(hammer2_iocom_t *iocom) | |
| 119 | { | |
| 120 | sockaddr_any_t sa; | |
| 121 | socklen_t salen = sizeof(sa); | |
| 122 | char peername[128]; | |
| 123 | char realname[128]; | |
| 124 | hammer2_handshake_t handtx; | |
| 125 | hammer2_handshake_t handrx; | |
| 5cf97ec5 MD |
126 | char buf1[sizeof(handtx)]; |
| 127 | char buf2[sizeof(handtx)]; | |
| 62efe6ec MD |
128 | char *ptr; |
| 129 | char *path; | |
| 130 | struct stat st; | |
| 131 | FILE *fp; | |
| 132 | RSA *keys[3] = { NULL, NULL, NULL }; | |
| 133 | size_t i; | |
| 134 | size_t blksize; | |
| 135 | size_t blkmask; | |
| 136 | ssize_t n; | |
| 137 | int fd; | |
| 138 | ||
| 139 | /* | |
| 140 | * Get the peer IP address for the connection as a string. | |
| 141 | */ | |
| 142 | if (getpeername(iocom->sock_fd, &sa.sa, &salen) < 0) { | |
| 143 | iocom->ioq_rx.error = HAMMER2_IOQ_ERROR_NOPEER; | |
| 144 | iocom->flags |= HAMMER2_IOCOMF_EOF; | |
| 145 | if (DebugOpt) | |
| 146 | fprintf(stderr, "accept: getpeername() failed\n"); | |
| 147 | goto done; | |
| 148 | } | |
| 149 | if (getnameinfo(&sa.sa, salen, peername, sizeof(peername), | |
| 150 | NULL, 0, NI_NUMERICHOST) < 0) { | |
| 151 | iocom->ioq_rx.error = HAMMER2_IOQ_ERROR_NOPEER; | |
| 152 | iocom->flags |= HAMMER2_IOCOMF_EOF; | |
| 153 | if (DebugOpt) | |
| 154 | fprintf(stderr, "accept: cannot decode sockaddr\n"); | |
| 155 | goto done; | |
| 156 | } | |
| 157 | if (DebugOpt) { | |
| 158 | if (realhostname_sa(realname, sizeof(realname), | |
| 159 | &sa.sa, salen) == HOSTNAME_FOUND) { | |
| 160 | fprintf(stderr, "accept from %s (%s)\n", | |
| 161 | peername, realname); | |
| 162 | } else { | |
| 163 | fprintf(stderr, "accept from %s\n", peername); | |
| 164 | } | |
| 165 | } | |
| 166 | ||
| 167 | /* | |
| 168 | * Find the remote host's public key | |
| 9b8b748f MD |
169 | * |
| 170 | * If the link is not to be encrypted (<ip>.none located) we shortcut | |
| 171 | * the handshake entirely. No buffers are exchanged. | |
| 62efe6ec MD |
172 | */ |
| 173 | asprintf(&path, "%s/%s.pub", HAMMER2_PATH_REMOTE, peername); | |
| 174 | if ((fp = fopen(path, "r")) == NULL) { | |
| 175 | free(path); | |
| 176 | asprintf(&path, "%s/%s.none", | |
| 177 | HAMMER2_PATH_REMOTE, peername); | |
| 178 | if (stat(path, &st) < 0) { | |
| 179 | iocom->ioq_rx.error = HAMMER2_IOQ_ERROR_NORKEY; | |
| 180 | iocom->flags |= HAMMER2_IOCOMF_EOF; | |
| 181 | if (DebugOpt) | |
| 182 | fprintf(stderr, "auth failure: unknown host\n"); | |
| 183 | goto done; | |
| 184 | } | |
| 185 | if (DebugOpt) | |
| 186 | fprintf(stderr, "auth succeeded, unencrypted link\n"); | |
| 9b8b748f | 187 | goto done; |
| 62efe6ec MD |
188 | } |
| 189 | if (fp) { | |
| 190 | keys[0] = PEM_read_RSA_PUBKEY(fp, NULL, NULL, NULL); | |
| 191 | fclose(fp); | |
| 192 | if (keys[0] == NULL) { | |
| 193 | iocom->ioq_rx.error = HAMMER2_IOQ_ERROR_KEYFMT; | |
| 194 | iocom->flags |= HAMMER2_IOCOMF_EOF; | |
| 195 | if (DebugOpt) | |
| 196 | fprintf(stderr, | |
| 197 | "auth failure: bad key format\n"); | |
| 198 | goto done; | |
| 199 | } | |
| 200 | } | |
| 201 | ||
| 202 | /* | |
| 203 | * Get our public and private keys | |
| 204 | */ | |
| 205 | free(path); | |
| 206 | asprintf(&path, HAMMER2_DEFAULT_DIR "/rsa.pub"); | |
| 207 | if ((fp = fopen(path, "r")) == NULL) { | |
| 208 | iocom->ioq_rx.error = HAMMER2_IOQ_ERROR_NOLKEY; | |
| 209 | iocom->flags |= HAMMER2_IOCOMF_EOF; | |
| 210 | goto done; | |
| 211 | } | |
| 212 | keys[1] = PEM_read_RSA_PUBKEY(fp, NULL, NULL, NULL); | |
| 213 | fclose(fp); | |
| 214 | if (keys[1] == NULL) { | |
| 215 | iocom->ioq_rx.error = HAMMER2_IOQ_ERROR_KEYFMT; | |
| 216 | iocom->flags |= HAMMER2_IOCOMF_EOF; | |
| 217 | if (DebugOpt) | |
| 218 | fprintf(stderr, "auth failure: bad host key format\n"); | |
| 219 | goto done; | |
| 220 | } | |
| 221 | ||
| 222 | free(path); | |
| 223 | asprintf(&path, HAMMER2_DEFAULT_DIR "/rsa.prv"); | |
| 224 | if ((fp = fopen(path, "r")) == NULL) { | |
| 225 | iocom->ioq_rx.error = HAMMER2_IOQ_ERROR_NOLKEY; | |
| 226 | iocom->flags |= HAMMER2_IOCOMF_EOF; | |
| 227 | if (DebugOpt) | |
| 228 | fprintf(stderr, "auth failure: bad host key format\n"); | |
| 229 | goto done; | |
| 230 | } | |
| 231 | keys[2] = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL); | |
| 232 | fclose(fp); | |
| 233 | if (keys[2] == NULL) { | |
| 234 | iocom->ioq_rx.error = HAMMER2_IOQ_ERROR_KEYFMT; | |
| 235 | iocom->flags |= HAMMER2_IOCOMF_EOF; | |
| 236 | if (DebugOpt) | |
| 237 | fprintf(stderr, "auth failure: bad host key format\n"); | |
| 238 | goto done; | |
| 239 | } | |
| 240 | free(path); | |
| 241 | path = NULL; | |
| 242 | ||
| 243 | /* | |
| 244 | * public key encrypt/decrypt block size. | |
| 245 | */ | |
| 246 | if (keys[0]) { | |
| 247 | blksize = (size_t)RSA_size(keys[0]); | |
| 248 | if (blksize != (size_t)RSA_size(keys[1]) || | |
| 249 | blksize != (size_t)RSA_size(keys[2]) || | |
| 250 | sizeof(handtx) % blksize != 0) { | |
| 251 | iocom->ioq_rx.error = HAMMER2_IOQ_ERROR_KEYFMT; | |
| 252 | iocom->flags |= HAMMER2_IOCOMF_EOF; | |
| 253 | if (DebugOpt) | |
| 254 | fprintf(stderr, "auth failure: " | |
| 255 | "key size mismatch\n"); | |
| 256 | goto done; | |
| 257 | } | |
| 258 | } else { | |
| 259 | blksize = sizeof(handtx); | |
| 260 | } | |
| 261 | blkmask = blksize - 1; | |
| 262 | ||
| 263 | bzero(&handrx, sizeof(handrx)); | |
| 264 | bzero(&handtx, sizeof(handtx)); | |
| 265 | ||
| 266 | /* | |
| 267 | * Fill all unused fields (particular all junk fields) with random | |
| 268 | * data, and also set the session key. | |
| 269 | */ | |
| 270 | fd = open("/dev/urandom", O_RDONLY); | |
| 271 | if (fd < 0 || | |
| 272 | fstat(fd, &st) < 0 || /* something wrong */ | |
| 273 | S_ISREG(st.st_mode) || /* supposed to be a RNG dev! */ | |
| 274 | read(fd, &handtx, sizeof(handtx)) != sizeof(handtx)) { | |
| 275 | urandfail: | |
| 276 | if (fd >= 0) | |
| 277 | close(fd); | |
| 278 | iocom->ioq_rx.error = HAMMER2_IOQ_ERROR_BADURANDOM; | |
| 279 | iocom->flags |= HAMMER2_IOCOMF_EOF; | |
| 280 | if (DebugOpt) | |
| 281 | fprintf(stderr, "auth failure: bad rng\n"); | |
| 282 | goto done; | |
| 283 | } | |
| 284 | if (bcmp(&handrx, &handtx, sizeof(handtx)) == 0) | |
| 285 | goto urandfail; /* read all zeros */ | |
| 286 | close(fd); | |
| 5cf97ec5 | 287 | /* ERR_load_crypto_strings(); openssl debugging */ |
| 62efe6ec MD |
288 | |
| 289 | /* | |
| 290 | * Handshake with the remote. | |
| 291 | * | |
| 292 | * Encrypt with my private and remote's public | |
| 293 | * Decrypt with my private and remote's public | |
| 294 | * | |
| 295 | * When encrypting we have to make sure our buffer fits within the | |
| 296 | * modulus, which typically requires bit 7 o the first byte to be | |
| 297 | * zero. To be safe make sure that bit 7 and bit 6 is zero. | |
| 298 | */ | |
| 299 | snprintf(handtx.quickmsg, sizeof(handtx.quickmsg), "Testing 1 2 3"); | |
| 300 | handtx.magic = HAMMER2_MSGHDR_MAGIC; | |
| 301 | handtx.version = 1; | |
| 302 | handtx.flags = 0; | |
| 303 | assert(sizeof(handtx.verf) * 4 == sizeof(handtx.sess)); | |
| 304 | bzero(handtx.verf, sizeof(handtx.verf)); | |
| 305 | ||
| 306 | handtx.pad1[0] &= 0x3f; /* message must fit within modulus */ | |
| 307 | handtx.pad2[0] &= 0x3f; /* message must fit within modulus */ | |
| 308 | ||
| 309 | for (i = 0; i < sizeof(handtx.sess); ++i) | |
| 310 | handtx.verf[i / 4] ^= handtx.sess[i]; | |
| 311 | ||
| 312 | /* | |
| 313 | * Write handshake buffer to remote | |
| 314 | */ | |
| 315 | for (i = 0; i < sizeof(handtx); i += blksize) { | |
| 316 | ptr = (char *)&handtx + i; | |
| 317 | if (keys[0]) { | |
| 318 | /* | |
| 319 | * Since we are double-encrypting we have to make | |
| 320 | * sure that the result of the first stage does | |
| 321 | * not blow out the modulus for the second stage. | |
| 322 | * | |
| 323 | * The pointer is pointing to the pad*[] area so | |
| 324 | * we can mess with that until the first stage | |
| 325 | * is legal. | |
| 326 | */ | |
| 327 | do { | |
| 328 | ++*(int *)(ptr + 4); | |
| 5cf97ec5 | 329 | if (RSA_private_encrypt(blksize, ptr, buf1, |
| 62efe6ec MD |
330 | keys[2], RSA_NO_PADDING) < 0) { |
| 331 | iocom->ioq_rx.error = | |
| 332 | HAMMER2_IOQ_ERROR_KEYXCHGFAIL; | |
| 333 | } | |
| 5cf97ec5 | 334 | } while (buf1[0] & 0xC0); |
| 62efe6ec | 335 | |
| 5cf97ec5 | 336 | if (RSA_public_encrypt(blksize, buf1, buf2, |
| 62efe6ec MD |
337 | keys[0], RSA_NO_PADDING) < 0) { |
| 338 | iocom->ioq_rx.error = | |
| 339 | HAMMER2_IOQ_ERROR_KEYXCHGFAIL; | |
| 340 | } | |
| 341 | } | |
| 5cf97ec5 | 342 | if (write(iocom->sock_fd, buf2, blksize) != (ssize_t)blksize) { |
| 62efe6ec MD |
343 | fprintf(stderr, "WRITE ERROR\n"); |
| 344 | } | |
| 345 | } | |
| 346 | if (iocom->ioq_rx.error) { | |
| 347 | iocom->flags |= HAMMER2_IOCOMF_EOF; | |
| 348 | if (DebugOpt) | |
| 349 | fprintf(stderr, "auth failure: key exchange failure " | |
| 350 | "during encryption\n"); | |
| 351 | goto done; | |
| 352 | } | |
| 353 | ||
| 354 | /* | |
| 355 | * Read handshake buffer from remote | |
| 356 | */ | |
| 357 | i = 0; | |
| 358 | while (i < sizeof(handrx)) { | |
| 359 | ptr = (char *)&handrx + i; | |
| 360 | n = read(iocom->sock_fd, ptr, blksize - (i & blkmask)); | |
| 361 | if (n <= 0) | |
| 362 | break; | |
| 363 | ptr -= (i & blkmask); | |
| 364 | i += n; | |
| 365 | if (keys[0] && (i & blkmask) == 0) { | |
| 5cf97ec5 | 366 | if (RSA_private_decrypt(blksize, ptr, buf1, |
| 62efe6ec MD |
367 | keys[2], RSA_NO_PADDING) < 0) |
| 368 | iocom->ioq_rx.error = | |
| 369 | HAMMER2_IOQ_ERROR_KEYXCHGFAIL; | |
| 5cf97ec5 | 370 | if (RSA_public_decrypt(blksize, buf1, ptr, |
| 62efe6ec MD |
371 | keys[0], RSA_NO_PADDING) < 0) |
| 372 | iocom->ioq_rx.error = | |
| 373 | HAMMER2_IOQ_ERROR_KEYXCHGFAIL; | |
| 374 | } | |
| 375 | } | |
| 376 | if (iocom->ioq_rx.error) { | |
| 377 | iocom->flags |= HAMMER2_IOCOMF_EOF; | |
| 378 | if (DebugOpt) | |
| 379 | fprintf(stderr, "auth failure: key exchange failure " | |
| 380 | "during decryption\n"); | |
| 381 | goto done; | |
| 382 | } | |
| 383 | ||
| 384 | /* | |
| 385 | * Validate the received data. Try to make this a constant-time | |
| 386 | * algorithm. | |
| 387 | */ | |
| 388 | if (i != sizeof(handrx)) { | |
| 389 | keyxchgfail: | |
| 390 | iocom->ioq_rx.error = HAMMER2_IOQ_ERROR_KEYXCHGFAIL; | |
| 391 | iocom->flags |= HAMMER2_IOCOMF_EOF; | |
| 392 | if (DebugOpt) | |
| 393 | fprintf(stderr, "auth failure: key exchange failure\n"); | |
| 394 | goto done; | |
| 395 | } | |
| 396 | ||
| 397 | if (handrx.magic == HAMMER2_MSGHDR_MAGIC_REV) { | |
| 398 | handrx.version = bswap16(handrx.version); | |
| 399 | handrx.flags = bswap32(handrx.flags); | |
| 400 | } | |
| 401 | for (i = 0; i < sizeof(handrx.sess); ++i) | |
| 402 | handrx.verf[i / 4] ^= handrx.sess[i]; | |
| 403 | n = 0; | |
| 404 | for (i = 0; i < sizeof(handrx.verf); ++i) | |
| 405 | n += handrx.verf[i]; | |
| 406 | if (handrx.version != 1) | |
| 407 | ++n; | |
| 408 | if (n != 0) | |
| 409 | goto keyxchgfail; | |
| 410 | ||
| 5cf97ec5 MD |
411 | /* |
| 412 | * Calculate the session key and initialize the iv[]. | |
| 413 | */ | |
| 414 | assert(HAMMER2_AES_KEY_SIZE * 2 == sizeof(handrx.sess)); | |
| 415 | for (i = 0; i < HAMMER2_AES_KEY_SIZE; ++i) { | |
| 416 | iocom->sess[i] = handrx.sess[i] ^ handtx.sess[i]; | |
| 417 | iocom->ioq_rx.iv[i] = handrx.sess[HAMMER2_AES_KEY_SIZE + i] ^ | |
| 418 | handtx.sess[HAMMER2_AES_KEY_SIZE + i]; | |
| 419 | iocom->ioq_tx.iv[i] = handrx.sess[HAMMER2_AES_KEY_SIZE + i] ^ | |
| 420 | handtx.sess[HAMMER2_AES_KEY_SIZE + i]; | |
| 62efe6ec | 421 | } |
| 5cf97ec5 MD |
422 | printf("sess: "); |
| 423 | for (i = 0; i < HAMMER2_AES_KEY_SIZE; ++i) | |
| 424 | printf("%02x", (unsigned char)iocom->sess[i]); | |
| 425 | printf("\n"); | |
| 426 | printf("iv: "); | |
| 427 | for (i = 0; i < HAMMER2_AES_KEY_SIZE; ++i) | |
| 428 | printf("%02x", (unsigned char)iocom->ioq_rx.iv[i]); | |
| 429 | printf("\n"); | |
| 430 | ||
| 431 | EVP_CIPHER_CTX_init(&iocom->ioq_rx.ctx); | |
| 432 | EVP_DecryptInit_ex(&iocom->ioq_rx.ctx, HAMMER2_AES_TYPE_EVP, NULL, | |
| 433 | iocom->sess, iocom->ioq_rx.iv); | |
| 434 | EVP_CIPHER_CTX_set_padding(&iocom->ioq_rx.ctx, 0); | |
| 435 | ||
| 436 | EVP_CIPHER_CTX_init(&iocom->ioq_tx.ctx); | |
| 437 | EVP_EncryptInit_ex(&iocom->ioq_tx.ctx, HAMMER2_AES_TYPE_EVP, NULL, | |
| 438 | iocom->sess, iocom->ioq_tx.iv); | |
| 439 | EVP_CIPHER_CTX_set_padding(&iocom->ioq_tx.ctx, 0); | |
| 440 | ||
| 441 | iocom->flags |= HAMMER2_IOCOMF_CRYPTED; | |
| 442 | ||
| 443 | if (DebugOpt) | |
| 444 | fprintf(stderr, "auth success: %s\n", handrx.quickmsg); | |
| 62efe6ec MD |
445 | done: |
| 446 | if (path) | |
| 447 | free(path); | |
| 448 | if (keys[0]) | |
| 449 | RSA_free(keys[0]); | |
| 450 | if (keys[1]) | |
| 451 | RSA_free(keys[1]); | |
| 452 | if (keys[1]) | |
| 453 | RSA_free(keys[2]); | |
| 454 | } | |
| 5cf97ec5 MD |
455 | |
| 456 | /* | |
| 457 | * Decrypt pending data in the ioq's fifo. The data is decrypted in-place. | |
| 458 | */ | |
| 459 | void | |
| 460 | hammer2_crypto_decrypt(hammer2_iocom_t *iocom, hammer2_ioq_t *ioq) | |
| 461 | { | |
| 462 | int p_len; | |
| 463 | int n; | |
| 464 | int i; | |
| 465 | char buf[512]; | |
| 466 | ||
| 467 | if ((iocom->flags & HAMMER2_IOCOMF_CRYPTED) == 0) | |
| 468 | return; | |
| 469 | p_len = ioq->fifo_end - ioq->fifo_cdx; | |
| 470 | p_len &= ~HAMMER2_AES_KEY_MASK; | |
| 471 | if (p_len == 0) | |
| 472 | return; | |
| 473 | for (i = 0; i < p_len; i += n) { | |
| 474 | n = (p_len - i > (int)sizeof(buf)) ? | |
| 475 | (int)sizeof(buf) : p_len - i; | |
| 476 | bcopy(ioq->buf + ioq->fifo_cdx + i, buf, n); | |
| 477 | EVP_DecryptUpdate(&ioq->ctx, | |
| 478 | ioq->buf + ioq->fifo_cdx + i, &n, | |
| 479 | buf, n); | |
| 480 | } | |
| 481 | ioq->fifo_cdx += p_len; | |
| 482 | } | |
| 483 | ||
| 484 | /* | |
| 485 | * Decrypt data in the message's auxilary buffer. The data is decrypted | |
| 486 | * in-place. | |
| 487 | */ | |
| 488 | void | |
| 489 | hammer2_crypto_decrypt_aux(hammer2_iocom_t *iocom, hammer2_ioq_t *ioq, | |
| 490 | hammer2_msg_t *msg, int already) | |
| 491 | { | |
| 492 | int p_len; | |
| 493 | int n; | |
| 494 | int i; | |
| 495 | char buf[512]; | |
| 496 | ||
| 497 | if ((iocom->flags & HAMMER2_IOCOMF_CRYPTED) == 0) | |
| 498 | return; | |
| 499 | p_len = msg->aux_size; | |
| 500 | assert((p_len & HAMMER2_AES_KEY_MASK) == 0); | |
| 501 | if (p_len == 0) | |
| 502 | return; | |
| 503 | i = already; | |
| 504 | while (i < p_len) { | |
| 505 | n = (p_len - i > (int)sizeof(buf)) ? | |
| 506 | (int)sizeof(buf) : p_len - i; | |
| 507 | bcopy(msg->aux_data + i, buf, n); | |
| 508 | EVP_DecryptUpdate(&ioq->ctx, | |
| 509 | msg->aux_data + i, &n, | |
| 510 | buf, n); | |
| 511 | i += n; | |
| 512 | } | |
| 513 | #if 0 | |
| 514 | EVP_DecryptUpdate(&iocom->ioq_rx.ctx, | |
| 515 | msg->aux_data, &p_len, | |
| 516 | msg->aux_data, p_len); | |
| 517 | #endif | |
| 518 | } | |
| 519 | ||
| 520 | int | |
| 521 | hammer2_crypto_encrypt(hammer2_iocom_t *iocom, hammer2_ioq_t *ioq, | |
| 02454b3e | 522 | struct iovec *iov, int n, size_t *nmaxp) |
| 5cf97ec5 MD |
523 | { |
| 524 | int p_len; | |
| 525 | int i; | |
| 526 | int already; | |
| 527 | int nmax; | |
| 528 | ||
| 529 | if ((iocom->flags & HAMMER2_IOCOMF_CRYPTED) == 0) | |
| 530 | return (n); | |
| 531 | nmax = sizeof(ioq->buf) - ioq->fifo_cdx; /* max new bytes */ | |
| 532 | already = ioq->fifo_cdx - ioq->fifo_beg; /* already encrypted */ | |
| 533 | ||
| 534 | for (i = 0; i < n; ++i) { | |
| 535 | p_len = iov[i].iov_len; | |
| 536 | if (p_len <= already) { | |
| 537 | already -= p_len; | |
| 538 | continue; | |
| 539 | } | |
| 540 | p_len -= already; | |
| 02454b3e | 541 | p_len &= ~HAMMER2_AES_KEY_MASK; |
| 5cf97ec5 MD |
542 | if (p_len > nmax) |
| 543 | p_len = nmax; | |
| 544 | EVP_EncryptUpdate(&ioq->ctx, | |
| 545 | ioq->buf + ioq->fifo_cdx, &p_len, | |
| 546 | (char *)iov[i].iov_base + already, p_len); | |
| 547 | ioq->fifo_cdx += p_len; | |
| 548 | ioq->fifo_end += p_len; | |
| 549 | nmax -= p_len; | |
| 550 | if (nmax == 0) | |
| 551 | break; | |
| 552 | already = 0; | |
| 553 | } | |
| 554 | iov[0].iov_base = ioq->buf + ioq->fifo_beg; | |
| 555 | iov[0].iov_len = ioq->fifo_cdx - ioq->fifo_beg; | |
| 02454b3e | 556 | *nmaxp = (size_t)(ioq->fifo_cdx - ioq->fifo_beg); |
| 5cf97ec5 MD |
557 | |
| 558 | return (1); | |
| 559 | } | |
| 560 | ||
| 561 | void | |
| 562 | hammer2_crypto_encrypt_wrote(hammer2_iocom_t *iocom, hammer2_ioq_t *ioq, | |
| 563 | int nact) | |
| 564 | { | |
| 565 | if ((iocom->flags & HAMMER2_IOCOMF_CRYPTED) == 0) | |
| 566 | return; | |
| 567 | if (nact == 0) | |
| 568 | return; | |
| 569 | ioq->fifo_beg += nact; | |
| 570 | if (ioq->fifo_beg == ioq->fifo_end) { | |
| 571 | ioq->fifo_beg = 0; | |
| 572 | ioq->fifo_cdx = 0; | |
| 573 | ioq->fifo_end = 0; | |
| 574 | } | |
| 575 | } |