1/* SRP SASL plugin 2 * Ken Murchison 3 * Tim Martin 3/17/00 4 * $Id: srp.c,v 1.6 2006/01/24 20:37:26 snsimon Exp $ 5 */ 6/* 7 * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in 18 * the documentation and/or other materials provided with the 19 * distribution. 20 * 21 * 3. The name "Carnegie Mellon University" must not be used to 22 * endorse or promote products derived from this software without 23 * prior written permission. For permission or any other legal 24 * details, please contact 25 * Office of Technology Transfer 26 * Carnegie Mellon University 27 * 5000 Forbes Avenue 28 * Pittsburgh, PA 15213-3890 29 * (412) 268-4387, fax: (412) 268-7395 30 * tech-transfer@andrew.cmu.edu 31 * 32 * 4. Redistributions of any form whatsoever must retain the following 33 * acknowledgment: 34 * "This product includes software developed by Computing Services 35 * at Carnegie Mellon University (http://www.cmu.edu/computing/)." 36 * 37 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO 38 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 39 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE 40 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 41 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 42 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 43 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 44 */ 45 46/* 47 * Notes: 48 * 49 * - The authentication exchanges *should* be correct (per draft -08) 50 * but we won't know until we do some interop testing. 51 * 52 * - The security layers don't conform to draft -08: 53 * o We don't use eos() and os() elements in an SRP buffer, we send 54 * just the bare octets. 55 * o We don't yet use the PRNG() and KDF() primatives described in 56 * section 5.1. 57 * 58 * - Are we using cIV and sIV correctly for encrypt/decrypt? 59 * 60 * - We don't implement fast reauth. 61 */ 62 63#include <config.h> 64#include <assert.h> 65#include <ctype.h> 66#include <stdio.h> 67#include <limits.h> 68#include <stdarg.h> 69 70#ifndef UINT32_MAX 71#define UINT32_MAX 4294967295U 72#endif 73 74#if UINT_MAX == UINT32_MAX 75typedef unsigned int uint32; 76#elif ULONG_MAX == UINT32_MAX 77typedef unsigned long uint32; 78#elif USHRT_MAX == UINT32_MAX 79typedef unsigned short uint32; 80#else 81#error dont know what to use for uint32 82#endif 83 84/* for big number support */ 85#include <openssl/bn.h> 86 87/* for digest and cipher support */ 88#include <openssl/evp.h> 89#include <openssl/hmac.h> 90 91#include <sasl.h> 92#define MD5_H /* suppress internal MD5 */ 93#include <saslplug.h> 94 95#include "plugin_common.h" 96 97#ifdef macintosh 98#include <sasl_srp_plugin_decl.h> 99#endif 100 101/***************************** Common Section *****************************/ 102 103static const char plugin_id[] = "$Id: srp.c,v 1.6 2006/01/24 20:37:26 snsimon Exp $"; 104 105/* Size limit of cipher block size */ 106#define SRP_MAXBLOCKSIZE 16 107/* Size limit of SRP buffer */ 108#define SRP_MAXBUFFERSIZE 2147483643 109 110#define DEFAULT_MDA "SHA-1" 111 112#define OPTION_MDA "mda=" 113#define OPTION_REPLAY_DETECTION "replay_detection" 114#define OPTION_INTEGRITY "integrity=" 115#define OPTION_CONFIDENTIALITY "confidentiality=" 116#define OPTION_MANDATORY "mandatory=" 117#define OPTION_MAXBUFFERSIZE "maxbuffersize=" 118 119/* Table of recommended Modulus (base 16) and Generator pairs */ 120struct Ng { 121 char *N; 122 unsigned long g; 123} Ng_tab[] = { 124 /* [264 bits] */ 125 { "115B8B692E0E045692CF280B436735C77A5A9E8A9E7ED56C965F87DB5B2A2ECE3", 126 2 127 }, 128 /* [384 bits] */ 129 { "8025363296FB943FCE54BE717E0E2958A02A9672EF561953B2BAA3BAACC3ED5754EB764C7AB7184578C57D5949CCB41B", 130 2 131 }, 132 /* [512 bits] */ 133 { "D4C7F8A2B32C11B8FBA9581EC4BA4F1B04215642EF7355E37C0FC0443EF756EA2C6B8EEB755A1C723027663CAA265EF785B8FF6A9B35227A52D86633DBDFCA43", 134 2 135 }, 136 /* [640 bits] */ 137 { "C94D67EB5B1A2346E8AB422FC6A0EDAEDA8C7F894C9EEEC42F9ED250FD7F0046E5AF2CF73D6B2FA26BB08033DA4DE322E144E7A8E9B12A0E4637F6371F34A2071C4B3836CBEEAB15034460FAA7ADF483", 138 2 139 }, 140 /* [768 bits] */ 141 { "B344C7C4F8C495031BB4E04FF8F84EE95008163940B9558276744D91F7CC9F402653BE7147F00F576B93754BCDDF71B636F2099E6FFF90E79575F3D0DE694AFF737D9BE9713CEF8D837ADA6380B1093E94B6A529A8C6C2BE33E0867C60C3262B", 142 2 143 }, 144 /* [1024 bits] */ 145 { "EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE48E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B297BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9AFD5138FE8376435B9FC61D2FC0EB06E3", 146 2 147 }, 148 /* [1280 bits] */ 149 { "D77946826E811914B39401D56A0A7843A8E7575D738C672A090AB1187D690DC43872FC06A7B6A43F3B95BEAEC7DF04B9D242EBDC481111283216CE816E004B786C5FCE856780D41837D95AD787A50BBE90BD3A9C98AC0F5FC0DE744B1CDE1891690894BC1F65E00DE15B4B2AA6D87100C9ECC2527E45EB849DEB14BB2049B163EA04187FD27C1BD9C7958CD40CE7067A9C024F9B7C5A0B4F5003686161F0605B", 150 2 151 }, 152 /* [1536 bits] */ 153 { "9DEF3CAFB939277AB1F12A8617A47BBBDBA51DF499AC4C80BEEEA9614B19CC4D5F4F5F556E27CBDE51C6A94BE4607A291558903BA0D0F84380B655BB9A22E8DCDF028A7CEC67F0D08134B1C8B97989149B609E0BE3BAB63D47548381DBC5B1FC764E3F4B53DD9DA1158BFD3E2B9C8CF56EDF019539349627DB2FD53D24B7C48665772E437D6C7F8CE442734AF7CCB7AE837C264AE3A9BEB87F8A2FE9B8B5292E5A021FFF5E91479E8CE7A28C2442C6F315180F93499A234DCF76E3FED135F9BB", 154 2 155 }, 156 /* [2048 bits] */ 157 { "AC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF6095179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF747359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A436C6481F1D2B9078717461A5B9D32E688F87748544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB694B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F9E4AFF73", 158 2 159 } 160}; 161 162#define NUM_Ng (sizeof(Ng_tab) / sizeof(struct Ng)) 163 164 165typedef struct layer_option_s { 166 const char *name; /* name used in option strings */ 167 unsigned enabled; /* enabled? determined at run-time */ 168 unsigned bit; /* unique bit in bitmask */ 169 sasl_ssf_t ssf; /* ssf of layer */ 170 const char *evp_name; /* name used for lookup in EVP table */ 171} layer_option_t; 172 173static layer_option_t digest_options[] = { 174 { "SHA-1", 0, (1<<0), 1, "sha1" }, 175 { "RIPEMD-160", 0, (1<<1), 1, "rmd160" }, 176 { "MD5", 0, (1<<2), 1, "md5" }, 177 { NULL, 0, 0, 0, NULL } 178}; 179static layer_option_t *default_digest = &digest_options[0]; 180static layer_option_t *server_mda = NULL; 181 182static layer_option_t cipher_options[] = { 183 { "DES", 0, (1<<0), 56, "des-ofb" }, 184 { "3DES", 0, (1<<1), 112, "des-ede-ofb" }, 185 { "AES", 0, (1<<2), 128, "aes-128-ofb" }, 186 { "Blowfish", 0, (1<<3), 128, "bf-ofb" }, 187 { "CAST-128", 0, (1<<4), 128, "cast5-ofb" }, 188 { "IDEA", 0, (1<<5), 128, "idea-ofb" }, 189 { NULL, 0, 0, 0, NULL} 190}; 191/* XXX Hack until OpenSSL 0.9.7 */ 192#if OPENSSL_VERSION_NUMBER < 0x00907000L 193static layer_option_t *default_cipher = &cipher_options[0]; 194#else 195static layer_option_t *default_cipher = &cipher_options[2]; 196#endif 197 198 199enum { 200 BIT_REPLAY_DETECTION= (1<<0), 201 BIT_INTEGRITY= (1<<1), 202 BIT_CONFIDENTIALITY= (1<<2) 203}; 204 205typedef struct srp_options_s { 206 unsigned mda; /* bitmask of MDAs */ 207 unsigned replay_detection; /* replay detection on/off flag */ 208 unsigned integrity; /* bitmask of integrity layers */ 209 unsigned confidentiality; /* bitmask of confidentiality layers */ 210 unsigned mandatory; /* bitmask of mandatory layers */ 211 unsigned long maxbufsize; /* max # bytes processed by security layer */ 212} srp_options_t; 213 214/* The main SRP context */ 215typedef struct context { 216 int state; 217 218 BIGNUM N; /* safe prime modulus */ 219 BIGNUM g; /* generator */ 220 221 BIGNUM v; /* password verifier */ 222 223 BIGNUM b; /* server private key */ 224 BIGNUM B; /* server public key */ 225 226 BIGNUM a; /* client private key */ 227 BIGNUM A; /* client public key */ 228 229 char K[EVP_MAX_MD_SIZE]; /* shared context key */ 230 int Klen; 231 232 char M1[EVP_MAX_MD_SIZE]; /* client evidence */ 233 int M1len; 234 235 char *authid; /* authentication id (server) */ 236 char *userid; /* authorization id (server) */ 237 sasl_secret_t *password; /* user secret (client) */ 238 unsigned int free_password; /* set if we need to free password */ 239 240 char *client_options; 241 char *server_options; 242 243 srp_options_t client_opts; /* cache between client steps */ 244 char cIV[SRP_MAXBLOCKSIZE]; /* cache between client steps */ 245 246 char *salt; /* password salt */ 247 int saltlen; 248 249 const EVP_MD *md; /* underlying MDA */ 250 251 /* copy of utils from the params structures */ 252 const sasl_utils_t *utils; 253 254 /* per-step mem management */ 255 char *out_buf; 256 unsigned out_buf_len; 257 258 /* Layer foo */ 259 unsigned layer; /* bitmask of enabled layers */ 260 const EVP_MD *hmac_md; /* HMAC for integrity */ 261 HMAC_CTX hmac_send_ctx; 262 HMAC_CTX hmac_recv_ctx; 263 264 const EVP_CIPHER *cipher; /* cipher for confidentiality */ 265 EVP_CIPHER_CTX cipher_enc_ctx; 266 EVP_CIPHER_CTX cipher_dec_ctx; 267 268 /* replay detection sequence numbers */ 269 int seqnum_out; 270 int seqnum_in; 271 272 /* for encoding/decoding mem management */ 273 char *encode_buf, *decode_buf, *decode_pkt_buf; 274 unsigned encode_buf_len, decode_buf_len, decode_pkt_buf_len; 275 276 /* layers buffering */ 277 decode_context_t decode_context; 278 279} context_t; 280 281static int srp_encode(void *context, 282 const struct iovec *invec, 283 unsigned numiov, 284 const char **output, 285 unsigned *outputlen) 286{ 287 context_t *text = (context_t *) context; 288 unsigned i; 289 char *input; 290 unsigned long inputlen, tmpnum; 291 int ret; 292 293 if (!context || !invec || !numiov || !output || !outputlen) { 294 PARAMERROR( text->utils ); 295 return SASL_BADPARAM; 296 } 297 298 /* calculate total size of input */ 299 for (i = 0, inputlen = 0; i < numiov; i++) 300 inputlen += invec[i].iov_len; 301 302 /* allocate a buffer for the output */ 303 ret = _plug_buf_alloc(text->utils, &text->encode_buf, 304 &text->encode_buf_len, 305 4 + /* for length */ 306 inputlen + /* for content */ 307 SRP_MAXBLOCKSIZE + /* for PKCS padding */ 308 EVP_MAX_MD_SIZE); /* for HMAC */ 309 if (ret != SASL_OK) return ret; 310 311 *outputlen = 4; /* length */ 312 313 /* operate on each iovec */ 314 for (i = 0; i < numiov; i++) { 315 input = invec[i].iov_base; 316 inputlen = invec[i].iov_len; 317 318 if (text->layer & BIT_CONFIDENTIALITY) { 319 unsigned enclen; 320 321 /* encrypt the data into the output buffer */ 322 EVP_EncryptUpdate(&text->cipher_enc_ctx, 323 text->encode_buf + *outputlen, &enclen, 324 input, inputlen); 325 *outputlen += enclen; 326 327 /* switch the input to the encrypted data */ 328 input = text->encode_buf + 4; 329 inputlen = *outputlen - 4; 330 } 331 else { 332 /* copy the raw input to the output */ 333 memcpy(text->encode_buf + *outputlen, input, inputlen); 334 *outputlen += inputlen; 335 } 336 } 337 338 if (text->layer & BIT_CONFIDENTIALITY) { 339 unsigned enclen; 340 341 /* encrypt the last block of data into the output buffer */ 342 EVP_EncryptFinal(&text->cipher_enc_ctx, 343 text->encode_buf + *outputlen, &enclen); 344 *outputlen += enclen; 345 } 346 347 if (text->layer & BIT_INTEGRITY) { 348 unsigned hashlen; 349 350 /* hash the content */ 351 HMAC_Update(&text->hmac_send_ctx, text->encode_buf+4, *outputlen-4); 352 353 if (text->layer & BIT_REPLAY_DETECTION) { 354 /* hash the sequence number */ 355 tmpnum = htonl(text->seqnum_out); 356 HMAC_Update(&text->hmac_send_ctx, (char *) &tmpnum, 4); 357 358 text->seqnum_out++; 359 } 360 361 /* append the HMAC into the output buffer */ 362 HMAC_Final(&text->hmac_send_ctx, text->encode_buf + *outputlen, 363 &hashlen); 364 *outputlen += hashlen; 365 } 366 367 /* prepend the length of the output */ 368 tmpnum = *outputlen - 4; 369 tmpnum = htonl(tmpnum); 370 memcpy(text->encode_buf, &tmpnum, 4); 371 372 *output = text->encode_buf; 373 374 return SASL_OK; 375} 376 377/* decode a single SRP packet */ 378static int srp_decode_packet(void *context, 379 const char *input, 380 unsigned inputlen, 381 char **output, 382 unsigned *outputlen) 383{ 384 context_t *text = (context_t *) context; 385 int ret; 386 387 if (text->layer & BIT_INTEGRITY) { 388 const char *hash; 389 char myhash[EVP_MAX_MD_SIZE]; 390 unsigned hashlen, myhashlen, i; 391 unsigned long tmpnum; 392 393 hashlen = EVP_MD_size(text->hmac_md); 394 395 if (inputlen < hashlen) { 396 text->utils->seterror(text->utils->conn, 0, 397 "SRP input is smaller " 398 "than hash length: %d vs %d\n", 399 inputlen, hashlen); 400 return SASL_BADPROT; 401 } 402 403 inputlen -= hashlen; 404 hash = input + inputlen; 405 406 /* create our own hash from the input */ 407 HMAC_Update(&text->hmac_recv_ctx, input, inputlen); 408 409 if (text->layer & BIT_REPLAY_DETECTION) { 410 /* hash the sequence number */ 411 tmpnum = htonl(text->seqnum_in); 412 HMAC_Update(&text->hmac_recv_ctx, (char *) &tmpnum, 4); 413 414 text->seqnum_in++; 415 } 416 417 HMAC_Final(&text->hmac_recv_ctx, myhash, &myhashlen); 418 419 /* compare hashes */ 420 for (i = 0; i < hashlen; i++) { 421 if ((myhashlen != hashlen) || (myhash[i] != hash[i])) { 422 SETERROR(text->utils, "Hash is incorrect\n"); 423 return SASL_BADMAC; 424 } 425 } 426 } 427 428 ret = _plug_buf_alloc(text->utils, &(text->decode_pkt_buf), 429 &(text->decode_pkt_buf_len), 430 inputlen); 431 if (ret != SASL_OK) return ret; 432 433 if (text->layer & BIT_CONFIDENTIALITY) { 434 unsigned declen; 435 436 /* decrypt the data into the output buffer */ 437 EVP_DecryptUpdate(&text->cipher_dec_ctx, 438 text->decode_pkt_buf, &declen, 439 (char *) input, inputlen); 440 *outputlen = declen; 441 442 EVP_DecryptFinal(&text->cipher_dec_ctx, 443 text->decode_pkt_buf + declen, &declen); 444 *outputlen += declen; 445 } else { 446 /* copy the raw input to the output */ 447 memcpy(text->decode_pkt_buf, input, inputlen); 448 *outputlen = inputlen; 449 } 450 451 *output = text->decode_pkt_buf; 452 453 return SASL_OK; 454} 455 456/* decode and concatenate multiple SRP packets */ 457static int srp_decode(void *context, 458 const char *input, unsigned inputlen, 459 const char **output, unsigned *outputlen) 460{ 461 context_t *text = (context_t *) context; 462 int ret; 463 464 ret = _plug_decode(&text->decode_context, input, inputlen, 465 &text->decode_buf, &text->decode_buf_len, outputlen, 466 srp_decode_packet, text); 467 468 *output = text->decode_buf; 469 470 return ret; 471} 472 473/* 474 * Convert a big integer to it's byte representation 475 */ 476static int BigIntToBytes(BIGNUM *num, char *out, int maxoutlen, int *outlen) 477{ 478 int len; 479 480 len = BN_num_bytes(num); 481 482 if (len > maxoutlen) return SASL_FAIL; 483 484 *outlen = BN_bn2bin(num, out); 485 486 return SASL_OK; 487} 488 489/* 490 * Compare a big integer against a word. 491 */ 492static int BigIntCmpWord(BIGNUM *a, BN_ULONG w) 493{ 494 BIGNUM *b = BN_new(); 495 int r; 496 497 BN_set_word(b, w); 498 r = BN_cmp(a, b); 499 BN_free(b); 500 return r; 501} 502 503/* 504 * Generate a random big integer. 505 */ 506static void GetRandBigInt(BIGNUM *out) 507{ 508 BN_init(out); 509 510 /* xxx likely should use sasl random funcs */ 511 BN_rand(out, SRP_MAXBLOCKSIZE*8, 0, 0); 512} 513 514#define MAX_BUFFER_LEN 2147483643 515#define MAX_MPI_LEN 65535 516#define MAX_UTF8_LEN 65535 517#define MAX_OS_LEN 255 518 519/* 520 * Make an SRP buffer from the data specified by the fmt string. 521 */ 522static int MakeBuffer(const sasl_utils_t *utils, char **buf, unsigned *buflen, 523 unsigned *outlen, const char *fmt, ...) 524{ 525 va_list ap; 526 char *p, *out = NULL; 527 int r, alloclen, len; 528 BIGNUM *mpi; 529 char *os, *str, c; 530 uint32 u; 531 short ns; 532 long totlen; 533 534 /* first pass to calculate size of buffer */ 535 va_start(ap, fmt); 536 for (p = (char *) fmt, alloclen = 0; *p; p++) { 537 if (*p != '%') { 538 alloclen++; 539 continue; 540 } 541 542 switch (*++p) { 543 case 'm': 544 /* MPI */ 545 mpi = va_arg(ap, BIGNUM *); 546 len = BN_num_bytes(mpi); 547 if (len > MAX_MPI_LEN) { 548 utils->log(NULL, SASL_LOG_ERR, 549 "String too long to create mpi string\n"); 550 r = SASL_FAIL; 551 goto done; 552 } 553 alloclen += len + 2; 554 break; 555 556 case 'o': 557 /* octet sequence (len followed by data) */ 558 len = va_arg(ap, int); 559 if (len > MAX_OS_LEN) { 560 utils->log(NULL, SASL_LOG_ERR, 561 "String too long to create os string\n"); 562 r = SASL_FAIL; 563 goto done; 564 } 565 alloclen += len + 1; 566 os = va_arg(ap, char *); 567 break; 568 569 case 's': 570 /* string */ 571 str = va_arg(ap, char *); 572 len = strlen(str); 573 if (len > MAX_UTF8_LEN) { 574 utils->log(NULL, SASL_LOG_ERR, 575 "String too long to create utf8 string\n"); 576 r = SASL_FAIL; 577 goto done; 578 } 579 alloclen += len + 2; 580 break; 581 582 case 'u': 583 /* unsigned int */ 584 u = va_arg(ap, uint32); 585 alloclen += sizeof(uint32); 586 break; 587 588 case 'c': 589 /* char */ 590 c = va_arg(ap, int) & 0xFF; 591 alloclen += 1; 592 break; 593 594 default: 595 alloclen += 1; 596 break; 597 } 598 } 599 va_end(ap); 600 601 if (alloclen > MAX_BUFFER_LEN) { 602 utils->log(NULL, SASL_LOG_ERR, 603 "String too long to create SRP buffer string\n"); 604 return SASL_FAIL; 605 } 606 607 alloclen += 4; 608 r = _plug_buf_alloc(utils, buf, buflen, alloclen); 609 if (r != SASL_OK) return r; 610 611 out = *buf + 4; /* skip size for now */ 612 613 /* second pass to fill buffer */ 614 va_start(ap, fmt); 615 for (p = (char *) fmt; *p; p++) { 616 if (*p != '%') { 617 *out = *p; 618 out++; 619 continue; 620 } 621 622 switch (*++p) { 623 case 'm': 624 /* MPI */ 625 mpi = va_arg(ap, BIGNUM *); 626 r = BigIntToBytes(mpi, out+2, BN_num_bytes(mpi), &len); 627 if (r) goto done; 628 ns = htons(len); 629 memcpy(out, &ns, 2); /* add 2 byte len (network order) */ 630 out += len + 2; 631 break; 632 633 case 'o': 634 /* octet sequence (len followed by data) */ 635 len = va_arg(ap, int); 636 os = va_arg(ap, char *); 637 *out = len & 0xFF; /* add 1 byte len */ 638 memcpy(out+1, os, len); /* add data */ 639 out += len+1; 640 break; 641 642 case 's': 643 /* string */ 644 str = va_arg(ap, char *); 645 /* xxx do actual utf8 conversion */ 646 len = strlen(str); 647 ns = htons(len); 648 memcpy(out, &ns, 2); /* add 2 byte len (network order) */ 649 memcpy(out+2, str, len); /* add string */ 650 out += len + 2; 651 break; 652 653 case 'u': 654 /* unsigned int */ 655 u = va_arg(ap, uint32); 656 u = htonl(u); 657 memcpy(out, &u, sizeof(uint32)); 658 out += sizeof(uint32); 659 break; 660 661 case 'c': 662 /* char */ 663 c = va_arg(ap, int) & 0xFF; 664 *out = c; 665 out++; 666 break; 667 668 default: 669 *out = *p; 670 out++; 671 break; 672 } 673 } 674 done: 675 va_end(ap); 676 677 *outlen = out - *buf; 678 679 /* add 4 byte len (network order) */ 680 totlen = htonl(*outlen - 4); 681 memcpy(*buf, &totlen, 4); 682 683 return r; 684} 685 686/* 687 * Extract an SRP buffer into the data specified by the fmt string. 688 * 689 * A '-' flag means don't allocate memory for the data ('o' only). 690 */ 691static int UnBuffer(const sasl_utils_t *utils, const char *buf, 692 unsigned buflen, const char *fmt, ...) 693{ 694 va_list ap; 695 char *p; 696 int r = SASL_OK, noalloc; 697 BIGNUM *mpi; 698 char **os, **str; 699 uint32 *u; 700 unsigned short ns; 701 unsigned len; 702 703 if (!buf || buflen < 4) { 704 utils->seterror(utils->conn, 0, 705 "Buffer is not big enough to be SRP buffer: %d\n", 706 buflen); 707 return SASL_BADPROT; 708 } 709 710 /* get the length */ 711 memcpy(&len, buf, 4); 712 len = ntohl(len); 713 buf += 4; 714 buflen -= 4; 715 716 /* make sure it's right */ 717 if (len != buflen) { 718 SETERROR(utils, "SRP Buffer isn't of the right length\n"); 719 return SASL_BADPROT; 720 } 721 722 va_start(ap, fmt); 723 for (p = (char *) fmt; *p; p++) { 724 if (*p != '%') { 725 if (*buf != *p) { 726 r = SASL_BADPROT; 727 goto done; 728 } 729 buf++; 730 buflen--; 731 continue; 732 } 733 734 /* check for noalloc flag */ 735 if ((noalloc = (*++p == '-'))) ++p; 736 737 switch (*p) { 738 case 'm': 739 /* MPI */ 740 if (buflen < 2) { 741 SETERROR(utils, "Buffer is not big enough to be SRP MPI\n"); 742 r = SASL_BADPROT; 743 goto done; 744 } 745 746 /* get the length */ 747 memcpy(&ns, buf, 2); 748 len = ntohs(ns); 749 buf += 2; 750 buflen -= 2; 751 752 /* make sure it's right */ 753 if (len > buflen) { 754 SETERROR(utils, "Not enough data for this SRP MPI\n"); 755 r = SASL_BADPROT; 756 goto done; 757 } 758 759 mpi = va_arg(ap, BIGNUM *); 760 BN_init(mpi); 761 BN_bin2bn(buf, len, mpi); 762 break; 763 764 case 'o': 765 /* octet sequence (len followed by data) */ 766 if (buflen < 1) { 767 SETERROR(utils, "Buffer is not big enough to be SRP os\n"); 768 r = SASL_BADPROT; 769 goto done; 770 } 771 772 /* get the length */ 773 len = (unsigned char) *buf; 774 buf++; 775 buflen--; 776 777 /* make sure it's right */ 778 if (len > buflen) { 779 SETERROR(utils, "Not enough data for this SRP os\n"); 780 r = SASL_BADPROT; 781 goto done; 782 } 783 784 *(va_arg(ap, int *)) = len; 785 os = va_arg(ap, char **); 786 787 if (noalloc) 788 *os = (char *) buf; 789 else { 790 *os = (char *) utils->malloc(len); 791 if (!*os) { 792 r = SASL_NOMEM; 793 goto done; 794 } 795 796 memcpy(*os, buf, len); 797 } 798 break; 799 800 case 's': 801 /* string */ 802 if (buflen < 2) { 803 SETERROR(utils, "Buffer is not big enough to be SRP UTF8\n"); 804 r = SASL_BADPROT; 805 goto done; 806 } 807 808 /* get the length */ 809 memcpy(&ns, buf, 2); 810 len = ntohs(ns); 811 buf += 2; 812 buflen -= 2; 813 814 /* make sure it's right */ 815 if (len > buflen) { 816 SETERROR(utils, "Not enough data for this SRP UTF8\n"); 817 r = SASL_BADPROT; 818 goto done; 819 } 820 821 str = va_arg(ap, char **); 822 *str = (char *) utils->malloc(len+1); /* +1 for NUL */ 823 if (!*str) { 824 r = SASL_NOMEM; 825 goto done; 826 } 827 828 memcpy(*str, buf, len); 829 (*str)[len] = '\0'; 830 break; 831 832 case 'u': 833 /* unsigned int */ 834 if (buflen < sizeof(uint32)) { 835 SETERROR(utils, "Buffer is not big enough to be SRP uint\n"); 836 r = SASL_BADPROT; 837 goto done; 838 } 839 840 len = sizeof(uint32); 841 u = va_arg(ap, uint32*); 842 memcpy(u, buf, len); 843 *u = ntohs(*u); 844 break; 845 846 case 'c': 847 /* char */ 848 if (buflen < 1) { 849 SETERROR(utils, "Buffer is not big enough to be SRP char\n"); 850 r = SASL_BADPROT; 851 goto done; 852 } 853 854 len = 1; 855 *(va_arg(ap, char *)) = *buf; 856 break; 857 858 default: 859 len = 1; 860 if (*buf != *p) { 861 r = SASL_BADPROT; 862 goto done; 863 } 864 break; 865 } 866 867 buf += len; 868 buflen -= len; 869 } 870 871 done: 872 va_end(ap); 873 874 if (buflen != 0) { 875 SETERROR(utils, "Extra data in SRP buffer\n"); 876 r = SASL_BADPROT; 877 } 878 879 return r; 880} 881 882/* 883 * Apply the hash function to the data specifed by the fmt string. 884 */ 885static int MakeHash(const EVP_MD *md, unsigned char hash[], int *hashlen, 886 const char *fmt, ...) 887{ 888 va_list ap; 889 char *p, buf[4096], *in; 890 int inlen; 891 EVP_MD_CTX mdctx; 892 int r = 0, hflag; 893 894 EVP_DigestInit(&mdctx, md); 895 896 va_start(ap, fmt); 897 for (p = (char *) fmt; *p; p++) { 898 if (*p != '%') { 899 in = p; 900 inlen = 1; 901 hflag = 0; 902 } 903 else { 904 if ((hflag = (*++p == 'h'))) ++p; 905 906 switch (*p) { 907 case 'm': { 908 /* MPI */ 909 BIGNUM *mval = va_arg(ap, BIGNUM *); 910 911 in = buf; 912 r = BigIntToBytes(mval, buf, sizeof(buf)-1, &inlen); 913 if (r) goto done; 914 break; 915 } 916 917 case 'o': { 918 /* octet sequence (len followed by data) */ 919 inlen = va_arg(ap, int); 920 in = va_arg(ap, char *); 921 break; 922 } 923 924 case 's': 925 /* string */ 926 in = va_arg(ap, char *); 927 inlen = strlen(in); 928 break; 929 930 case 'u': { 931 /* unsigned int */ 932 uint32 uval = va_arg(ap, uint32); 933 934 in = buf; 935 inlen = sizeof(uint32); 936 *((uint32 *) buf) = htonl(uval); 937 break; 938 } 939 940 default: 941 in = p; 942 inlen = 1; 943 break; 944 } 945 } 946 947 if (hflag) { 948 /* hash data separately before adding to current hash */ 949 EVP_MD_CTX tmpctx; 950 951 EVP_DigestInit(&tmpctx, md); 952 EVP_DigestUpdate(&tmpctx, in, inlen); 953 EVP_DigestFinal(&tmpctx, buf, &inlen); 954 in = buf; 955 } 956 957 EVP_DigestUpdate(&mdctx, in, inlen); 958 } 959 done: 960 va_end(ap); 961 962 EVP_DigestFinal(&mdctx, hash, hashlen); 963 964 return r; 965} 966 967static int CalculateX(context_t *text, const char *salt, int saltlen, 968 const char *user, const char *pass, int passlen, 969 BIGNUM *x) 970{ 971 char hash[EVP_MAX_MD_SIZE]; 972 int hashlen; 973 974 /* x = H(salt | H(user | ':' | pass)) */ 975 MakeHash(text->md, hash, &hashlen, "%s:%o", user, passlen, pass); 976 MakeHash(text->md, hash, &hashlen, "%o%o", saltlen, salt, hashlen, hash); 977 978 BN_init(x); 979 BN_bin2bn(hash, hashlen, x); 980 981 return SASL_OK; 982} 983 984static int CalculateM1(context_t *text, BIGNUM *N, BIGNUM *g, 985 char *U, char *salt, int saltlen, 986 BIGNUM *A, BIGNUM *B, char *K, int Klen, 987 char *I, char *L, char *M1, int *M1len) 988{ 989 int r, i, len; 990 unsigned char Nhash[EVP_MAX_MD_SIZE]; 991 unsigned char ghash[EVP_MAX_MD_SIZE]; 992 unsigned char Ng[EVP_MAX_MD_SIZE]; 993 994 /* bytes(H( bytes(N) )) ^ bytes( H( bytes(g) )) 995 ^ is the bitwise XOR operator. */ 996 r = MakeHash(text->md, Nhash, &len, "%m", N); 997 if (r) return r; 998 r = MakeHash(text->md, ghash, &len, "%m", g); 999 if (r) return r; 1000 1001 for (i = 0; i < len; i++) { 1002 Ng[i] = (Nhash[i] ^ ghash[i]); 1003 } 1004 1005 r = MakeHash(text->md, M1, M1len, "%o%hs%o%m%m%o%hs%hs", 1006 len, Ng, U, saltlen, salt, A, B, Klen, K, I, L); 1007 1008 return r; 1009} 1010 1011static int CalculateM2(context_t *text, BIGNUM *A, 1012 char *M1, int M1len, char *K, int Klen, 1013 char *I, char *o, char *sid, uint32 ttl, 1014 char *M2, int *M2len) 1015{ 1016 int r; 1017 1018 r = MakeHash(text->md, M2, M2len, "%m%o%o%hs%hs%s%u", 1019 A, M1len, M1, Klen, K, I, o, sid, ttl); 1020 1021 return r; 1022} 1023 1024/* Parse an option out of an option string 1025 * Place found option in 'option' 1026 * 'nextptr' points to rest of string or NULL if at end 1027 */ 1028static int ParseOption(const sasl_utils_t *utils, 1029 char *in, char **option, char **nextptr) 1030{ 1031 char *comma; 1032 int len; 1033 int i; 1034 1035 if (strlen(in) == 0) { 1036 *option = NULL; 1037 return SASL_OK; 1038 } 1039 1040 comma = strchr(in,','); 1041 if (comma == NULL) comma = in + strlen(in); 1042 1043 len = comma - in; 1044 1045 *option = utils->malloc(len + 1); 1046 if (!*option) return SASL_NOMEM; 1047 1048 /* lowercase string */ 1049 for (i = 0; i < len; i++) { 1050 (*option)[i] = tolower((int)in[i]); 1051 } 1052 (*option)[len] = '\0'; 1053 1054 if (*comma) { 1055 *nextptr = comma+1; 1056 } else { 1057 *nextptr = NULL; 1058 } 1059 1060 return SASL_OK; 1061} 1062 1063static int FindBit(char *name, layer_option_t *opts) 1064{ 1065 while (opts->name) { 1066 if (!strcasecmp(name, opts->name)) { 1067 return opts->bit; 1068 } 1069 1070 opts++; 1071 } 1072 1073 return 0; 1074} 1075 1076static layer_option_t *FindOptionFromBit(unsigned bit, layer_option_t *opts) 1077{ 1078 while (opts->name) { 1079 if (opts->bit == bit) { 1080 return opts; 1081 } 1082 1083 opts++; 1084 } 1085 1086 return NULL; 1087} 1088 1089static int ParseOptionString(const sasl_utils_t *utils, 1090 char *str, srp_options_t *opts, int isserver) 1091{ 1092 if (!strncasecmp(str, OPTION_MDA, strlen(OPTION_MDA))) { 1093 1094 int bit = FindBit(str+strlen(OPTION_MDA), digest_options); 1095 1096 if (isserver && (!bit || opts->mda)) { 1097 opts->mda = -1; 1098 if (!bit) 1099 utils->seterror(utils->conn, 0, 1100 "SRP MDA %s not supported\n", 1101 str+strlen(OPTION_MDA)); 1102 else 1103 SETERROR(utils, "Multiple SRP MDAs given\n"); 1104 return SASL_BADPROT; 1105 } 1106 1107 opts->mda |= bit; 1108 1109 } else if (!strcasecmp(str, OPTION_REPLAY_DETECTION)) { 1110 if (opts->replay_detection) { 1111 SETERROR(utils, "SRP Replay Detection option appears twice\n"); 1112 return SASL_BADPROT; 1113 } 1114 opts->replay_detection = 1; 1115 1116 } else if (!strncasecmp(str, OPTION_INTEGRITY, strlen(OPTION_INTEGRITY)) && 1117 !strncasecmp(str+strlen(OPTION_INTEGRITY), "HMAC-", 5)) { 1118 1119 int bit = FindBit(str+strlen(OPTION_INTEGRITY)+5, digest_options); 1120 1121 if (isserver && (!bit || opts->integrity)) { 1122 opts->integrity = -1; 1123 if (!bit) 1124 utils->seterror(utils->conn, 0, 1125 "SRP Integrity option %s not supported\n", 1126 str+strlen(OPTION_INTEGRITY)); 1127 else 1128 SETERROR(utils, "Multiple SRP Integrity options given\n"); 1129 return SASL_BADPROT; 1130 } 1131 1132 opts->integrity |= bit; 1133 1134 } else if (!strncasecmp(str, OPTION_CONFIDENTIALITY, 1135 strlen(OPTION_CONFIDENTIALITY))) { 1136 1137 int bit = FindBit(str+strlen(OPTION_CONFIDENTIALITY), 1138 cipher_options); 1139 1140 if (isserver && (!bit || opts->confidentiality)) { 1141 opts->confidentiality = -1; 1142 if (!bit) 1143 utils->seterror(utils->conn, 0, 1144 "SRP Confidentiality option %s not supported\n", 1145 str+strlen(OPTION_CONFIDENTIALITY)); 1146 else 1147 SETERROR(utils, 1148 "Multiple SRP Confidentiality options given\n"); 1149 return SASL_FAIL; 1150 } 1151 1152 opts->confidentiality |= bit; 1153 1154 } else if (!isserver && !strncasecmp(str, OPTION_MANDATORY, 1155 strlen(OPTION_MANDATORY))) { 1156 1157 char *layer = str+strlen(OPTION_MANDATORY); 1158 1159 if (!strcasecmp(layer, OPTION_REPLAY_DETECTION)) 1160 opts->mandatory |= BIT_REPLAY_DETECTION; 1161 else if (!strncasecmp(layer, OPTION_INTEGRITY, 1162 strlen(OPTION_INTEGRITY)-1)) 1163 opts->mandatory |= BIT_INTEGRITY; 1164 else if (!strncasecmp(layer, OPTION_CONFIDENTIALITY, 1165 strlen(OPTION_CONFIDENTIALITY)-1)) 1166 opts->mandatory |= BIT_CONFIDENTIALITY; 1167 else { 1168 utils->seterror(utils->conn, 0, 1169 "Mandatory SRP option %s not supported\n", layer); 1170 return SASL_BADPROT; 1171 } 1172 1173 } else if (!strncasecmp(str, OPTION_MAXBUFFERSIZE, 1174 strlen(OPTION_MAXBUFFERSIZE))) { 1175 1176 opts->maxbufsize = strtoul(str+strlen(OPTION_MAXBUFFERSIZE), NULL, 10); 1177 1178 if (opts->maxbufsize > SRP_MAXBUFFERSIZE) { 1179 utils->seterror(utils->conn, 0, 1180 "SRP Maxbuffersize %lu too big (> %lu)\n", 1181 opts->maxbufsize, SRP_MAXBUFFERSIZE); 1182 return SASL_BADPROT; 1183 } 1184 1185 } else { 1186 /* Ignore unknown options */ 1187 } 1188 1189 return SASL_OK; 1190} 1191 1192static int ParseOptions(const sasl_utils_t *utils, 1193 char *in, srp_options_t *out, int isserver) 1194{ 1195 int r; 1196 1197 memset(out, 0, sizeof(srp_options_t)); 1198 out->maxbufsize = SRP_MAXBUFFERSIZE; 1199 1200 while (in) { 1201 char *opt; 1202 1203 r = ParseOption(utils, in, &opt, &in); 1204 if (r) return r; 1205 1206 if (opt == NULL) return SASL_OK; 1207 1208 utils->log(NULL, SASL_LOG_DEBUG, "Got option: [%s]\n",opt); 1209 1210 r = ParseOptionString(utils, opt, out, isserver); 1211 utils->free(opt); 1212 1213 if (r) return r; 1214 } 1215 1216 return SASL_OK; 1217} 1218 1219static layer_option_t *FindBest(int available, sasl_ssf_t min_ssf, 1220 sasl_ssf_t max_ssf, layer_option_t *opts) 1221{ 1222 layer_option_t *best = NULL; 1223 1224 if (!available) return NULL; 1225 1226 while (opts->name) { 1227 if (opts->enabled && (available & opts->bit) && 1228 (opts->ssf >= min_ssf) && (opts->ssf <= max_ssf) && 1229 (!best || (opts->ssf > best->ssf))) { 1230 best = opts; 1231 } 1232 1233 opts++; 1234 } 1235 1236 return best; 1237} 1238 1239static int OptionsToString(const sasl_utils_t *utils, 1240 srp_options_t *opts, char **out) 1241{ 1242 char *ret = NULL; 1243 int alloced = 0; 1244 int first = 1; 1245 layer_option_t *optlist; 1246 1247 ret = utils->malloc(1); 1248 if (!ret) return SASL_NOMEM; 1249 alloced = 1; 1250 ret[0] = '\0'; 1251 1252 optlist = digest_options; 1253 while(optlist->name) { 1254 if (opts->mda & optlist->bit) { 1255 alloced += strlen(OPTION_MDA)+strlen(optlist->name)+1; 1256 ret = utils->realloc(ret, alloced); 1257 if (!ret) return SASL_NOMEM; 1258 1259 if (!first) strcat(ret, ","); 1260 strcat(ret, OPTION_MDA); 1261 strcat(ret, optlist->name); 1262 first = 0; 1263 } 1264 1265 optlist++; 1266 } 1267 1268 if (opts->replay_detection) { 1269 alloced += strlen(OPTION_REPLAY_DETECTION)+1; 1270 ret = utils->realloc(ret, alloced); 1271 if (!ret) return SASL_NOMEM; 1272 1273 if (!first) strcat(ret, ","); 1274 strcat(ret, OPTION_REPLAY_DETECTION); 1275 first = 0; 1276 } 1277 1278 optlist = digest_options; 1279 while(optlist->name) { 1280 if (opts->integrity & optlist->bit) { 1281 alloced += strlen(OPTION_INTEGRITY)+5+strlen(optlist->name)+1; 1282 ret = utils->realloc(ret, alloced); 1283 if (!ret) return SASL_NOMEM; 1284 1285 if (!first) strcat(ret, ","); 1286 strcat(ret, OPTION_INTEGRITY); 1287 strcat(ret, "HMAC-"); 1288 strcat(ret, optlist->name); 1289 first = 0; 1290 } 1291 1292 optlist++; 1293 } 1294 1295 optlist = cipher_options; 1296 while(optlist->name) { 1297 if (opts->confidentiality & optlist->bit) { 1298 alloced += strlen(OPTION_CONFIDENTIALITY)+strlen(optlist->name)+1; 1299 ret = utils->realloc(ret, alloced); 1300 if (!ret) return SASL_NOMEM; 1301 1302 if (!first) strcat(ret, ","); 1303 strcat(ret, OPTION_CONFIDENTIALITY); 1304 strcat(ret, optlist->name); 1305 first = 0; 1306 } 1307 1308 optlist++; 1309 } 1310 1311 if ((opts->integrity || opts->confidentiality) && 1312 opts->maxbufsize < SRP_MAXBUFFERSIZE) { 1313 alloced += strlen(OPTION_MAXBUFFERSIZE)+10+1; 1314 ret = utils->realloc(ret, alloced); 1315 if (!ret) return SASL_NOMEM; 1316 1317 if (!first) strcat(ret, ","); 1318 strcat(ret, OPTION_MAXBUFFERSIZE); 1319 sprintf(ret+strlen(ret), "%lu", opts->maxbufsize); 1320 first = 0; 1321 } 1322 1323 if (opts->mandatory & BIT_REPLAY_DETECTION) { 1324 alloced += strlen(OPTION_MANDATORY)+strlen(OPTION_REPLAY_DETECTION)+1; 1325 ret = utils->realloc(ret, alloced); 1326 if (!ret) return SASL_NOMEM; 1327 1328 if (!first) strcat(ret, ","); 1329 strcat(ret, OPTION_MANDATORY); 1330 strcat(ret, OPTION_REPLAY_DETECTION); 1331 first = 0; 1332 } 1333 1334 if (opts->mandatory & BIT_INTEGRITY) { 1335 alloced += strlen(OPTION_MANDATORY)+strlen(OPTION_INTEGRITY)-1+1; 1336 ret = utils->realloc(ret, alloced); 1337 if (!ret) return SASL_NOMEM; 1338 1339 if (!first) strcat(ret, ","); 1340 strcat(ret, OPTION_MANDATORY); 1341 strncat(ret, OPTION_INTEGRITY, strlen(OPTION_INTEGRITY)-1); 1342 /* terminate string */ 1343 ret[alloced-1] = '\0'; 1344 first = 0; 1345 } 1346 1347 if (opts->mandatory & BIT_CONFIDENTIALITY) { 1348 alloced += strlen(OPTION_MANDATORY)+strlen(OPTION_CONFIDENTIALITY)-1+1; 1349 ret = utils->realloc(ret, alloced); 1350 if (!ret) return SASL_NOMEM; 1351 1352 if (!first) strcat(ret, ","); 1353 strcat(ret, OPTION_MANDATORY); 1354 strncat(ret, OPTION_CONFIDENTIALITY, strlen(OPTION_CONFIDENTIALITY)-1); 1355 /* terminate string */ 1356 ret[alloced-1] = '\0'; 1357 first = 0; 1358 } 1359 1360 *out = ret; 1361 return SASL_OK; 1362} 1363 1364 1365/* 1366 * Set the selected MDA. 1367 */ 1368static int SetMDA(srp_options_t *opts, context_t *text) 1369{ 1370 layer_option_t *opt; 1371 1372 opt = FindOptionFromBit(opts->mda, digest_options); 1373 if (!opt) { 1374 text->utils->log(NULL, SASL_LOG_ERR, 1375 "Unable to find SRP MDA option now\n"); 1376 return SASL_FAIL; 1377 } 1378 1379 text->md = EVP_get_digestbyname(opt->evp_name); 1380 1381 return SASL_OK; 1382} 1383 1384/* 1385 * Setup the selected security layer. 1386 */ 1387static int LayerInit(srp_options_t *opts, context_t *text, 1388 sasl_out_params_t *oparams, char *enc_IV, char *dec_IV, 1389 unsigned maxbufsize) 1390{ 1391 layer_option_t *opt; 1392 1393 if ((opts->integrity == 0) && (opts->confidentiality == 0)) { 1394 oparams->encode = NULL; 1395 oparams->decode = NULL; 1396 oparams->mech_ssf = 0; 1397 text->utils->log(NULL, SASL_LOG_DEBUG, "Using no protection\n"); 1398 return SASL_OK; 1399 } 1400 1401 oparams->encode = &srp_encode; 1402 oparams->decode = &srp_decode; 1403 oparams->maxoutbuf = opts->maxbufsize - 4; /* account for 4-byte length */ 1404 1405 _plug_decode_init(&text->decode_context, text->utils, maxbufsize); 1406 1407 if (opts->replay_detection) { 1408 text->utils->log(NULL, SASL_LOG_DEBUG, "Using replay detection\n"); 1409 1410 text->layer |= BIT_REPLAY_DETECTION; 1411 1412 /* If no integrity layer specified, use default */ 1413 if (!opts->integrity) 1414 opts->integrity = default_digest->bit; 1415 } 1416 1417 if (opts->integrity) { 1418 text->utils->log(NULL, SASL_LOG_DEBUG, "Using integrity protection\n"); 1419 1420 text->layer |= BIT_INTEGRITY; 1421 1422 opt = FindOptionFromBit(opts->integrity, digest_options); 1423 if (!opt) { 1424 text->utils->log(NULL, SASL_LOG_ERR, 1425 "Unable to find SRP integrity layer option\n"); 1426 return SASL_FAIL; 1427 } 1428 1429 oparams->mech_ssf = opt->ssf; 1430 1431 /* Initialize the HMACs */ 1432 text->hmac_md = EVP_get_digestbyname(opt->evp_name); 1433 HMAC_Init(&text->hmac_send_ctx, text->K, text->Klen, text->hmac_md); 1434 HMAC_Init(&text->hmac_recv_ctx, text->K, text->Klen, text->hmac_md); 1435 1436 /* account for HMAC */ 1437 oparams->maxoutbuf -= EVP_MD_size(text->hmac_md); 1438 } 1439 1440 if (opts->confidentiality) { 1441 text->utils->log(NULL, SASL_LOG_DEBUG, 1442 "Using confidentiality protection\n"); 1443 1444 text->layer |= BIT_CONFIDENTIALITY; 1445 1446 opt = FindOptionFromBit(opts->confidentiality, cipher_options); 1447 if (!opt) { 1448 text->utils->log(NULL, SASL_LOG_ERR, 1449 "Unable to find SRP confidentiality layer option\n"); 1450 return SASL_FAIL; 1451 } 1452 1453 oparams->mech_ssf = opt->ssf; 1454 1455 /* Initialize the ciphers */ 1456 text->cipher = EVP_get_cipherbyname(opt->evp_name); 1457 1458 EVP_CIPHER_CTX_init(&text->cipher_enc_ctx); 1459 EVP_EncryptInit(&text->cipher_enc_ctx, text->cipher, text->K, enc_IV); 1460 1461 EVP_CIPHER_CTX_init(&text->cipher_dec_ctx); 1462 EVP_DecryptInit(&text->cipher_dec_ctx, text->cipher, text->K, dec_IV); 1463 } 1464 1465 return SASL_OK; 1466} 1467 1468static void LayerCleanup(context_t *text) 1469{ 1470 if (text->layer & BIT_INTEGRITY) { 1471 HMAC_cleanup(&text->hmac_send_ctx); 1472 HMAC_cleanup(&text->hmac_recv_ctx); 1473 } 1474 1475 if (text->layer & BIT_CONFIDENTIALITY) { 1476 EVP_CIPHER_CTX_cleanup(&text->cipher_enc_ctx); 1477 EVP_CIPHER_CTX_cleanup(&text->cipher_dec_ctx); 1478 } 1479} 1480 1481 1482/* 1483 * Dispose of a SRP context (could be server or client) 1484 */ 1485static void srp_common_mech_dispose(void *conn_context, 1486 const sasl_utils_t *utils) 1487{ 1488 context_t *text = (context_t *) conn_context; 1489 1490 if (!text) return; 1491 1492 BN_clear_free(&text->N); 1493 BN_clear_free(&text->g); 1494 BN_clear_free(&text->v); 1495 BN_clear_free(&text->b); 1496 BN_clear_free(&text->B); 1497 BN_clear_free(&text->a); 1498 BN_clear_free(&text->A); 1499 1500 if (text->authid) utils->free(text->authid); 1501 if (text->userid) utils->free(text->userid); 1502 if (text->free_password) _plug_free_secret(utils, &(text->password)); 1503 if (text->salt) utils->free(text->salt); 1504 1505 if (text->client_options) utils->free(text->client_options); 1506 if (text->server_options) utils->free(text->server_options); 1507 1508 LayerCleanup(text); 1509 _plug_decode_free(&text->decode_context); 1510 1511 if (text->encode_buf) utils->free(text->encode_buf); 1512 if (text->decode_buf) utils->free(text->decode_buf); 1513 if (text->decode_pkt_buf) utils->free(text->decode_pkt_buf); 1514 if (text->out_buf) utils->free(text->out_buf); 1515 1516 utils->free(text); 1517} 1518 1519static void 1520srp_common_mech_free(void *global_context __attribute__((unused)), 1521 const sasl_utils_t *utils __attribute__((unused))) 1522{ 1523 EVP_cleanup(); 1524} 1525 1526 1527/***************************** Server Section *****************************/ 1528 1529/* A large safe prime (N = 2q+1, where q is prime) 1530 * 1531 * Use N with the most bits from our table. 1532 * 1533 * All arithmetic is done modulo N 1534 */ 1535static int generate_N_and_g(BIGNUM *N, BIGNUM *g) 1536{ 1537 int result; 1538 1539 BN_init(N); 1540 result = BN_hex2bn(&N, Ng_tab[NUM_Ng-1].N); 1541 if (!result) return SASL_FAIL; 1542 1543 BN_init(g); 1544 BN_set_word(g, Ng_tab[NUM_Ng-1].g); 1545 1546 return SASL_OK; 1547} 1548 1549static int CalculateV(context_t *text, 1550 BIGNUM *N, BIGNUM *g, 1551 const char *user, 1552 const char *pass, unsigned passlen, 1553 BIGNUM *v, char **salt, int *saltlen) 1554{ 1555 BIGNUM x; 1556 BN_CTX *ctx = BN_CTX_new(); 1557 int r; 1558 1559 /* generate <salt> */ 1560 *saltlen = SRP_MAXBLOCKSIZE; 1561 *salt = (char *)text->utils->malloc(*saltlen); 1562 if (!*salt) return SASL_NOMEM; 1563 text->utils->rand(text->utils->rpool, *salt, *saltlen); 1564 1565 r = CalculateX(text, *salt, *saltlen, user, pass, passlen, &x); 1566 if (r) { 1567 text->utils->seterror(text->utils->conn, 0, 1568 "Error calculating 'x'"); 1569 return r; 1570 } 1571 1572 /* v = g^x % N */ 1573 BN_init(v); 1574 BN_mod_exp(v, g, &x, N, ctx); 1575 1576 BN_CTX_free(ctx); 1577 BN_clear_free(&x); 1578 1579 return r; 1580} 1581 1582static int CalculateB(context_t *text __attribute__((unused)), 1583 BIGNUM *v, BIGNUM *N, BIGNUM *g, BIGNUM *b, BIGNUM *B) 1584{ 1585 BIGNUM v3; 1586 BN_CTX *ctx = BN_CTX_new(); 1587 1588 /* Generate b */ 1589 GetRandBigInt(b); 1590 1591 /* Per [SRP]: make sure b > log[g](N) -- g is always 2 */ 1592 BN_add_word(b, BN_num_bits(N)); 1593 1594 /* B = (3v + g^b) % N */ 1595 BN_init(&v3); 1596 BN_set_word(&v3, 3); 1597 BN_mod_mul(&v3, &v3, v, N, ctx); 1598 BN_init(B); 1599 BN_mod_exp(B, g, b, N, ctx); 1600#if OPENSSL_VERSION_NUMBER >= 0x00907000L 1601 BN_mod_add(B, B, &v3, N, ctx); 1602#else 1603 BN_add(B, B, &v3); 1604 BN_mod(B, B, N, ctx); 1605#endif 1606 1607 BN_CTX_free(ctx); 1608 1609 return SASL_OK; 1610} 1611 1612static int ServerCalculateK(context_t *text, BIGNUM *v, 1613 BIGNUM *N, BIGNUM *A, BIGNUM *b, BIGNUM *B, 1614 char *K, int *Klen) 1615{ 1616 unsigned char hash[EVP_MAX_MD_SIZE]; 1617 int hashlen; 1618 BIGNUM u; 1619 BIGNUM base; 1620 BIGNUM S; 1621 BN_CTX *ctx = BN_CTX_new(); 1622 int r; 1623 1624 /* u = H(A | B) */ 1625 r = MakeHash(text->md, hash, &hashlen, "%m%m", A, B); 1626 if (r) return r; 1627 1628 BN_init(&u); 1629 BN_bin2bn(hash, hashlen, &u); 1630 1631 /* S = (Av^u) ^ b % N */ 1632 BN_init(&base); 1633 BN_mod_exp(&base, v, &u, N, ctx); 1634 BN_mod_mul(&base, &base, A, N, ctx); 1635 1636 BN_init(&S); 1637 BN_mod_exp(&S, &base, b, N, ctx); 1638 1639 /* per Tom Wu: make sure Av^u != 1 (mod N) */ 1640 if (BN_is_one(&base)) { 1641 SETERROR(text->utils, "Unsafe SRP value for 'Av^u'\n"); 1642 r = SASL_BADPROT; 1643 goto err; 1644 } 1645 1646 /* per Tom Wu: make sure Av^u != -1 (mod N) */ 1647 BN_add_word(&base, 1); 1648 if (BN_cmp(&S, N) == 0) { 1649 SETERROR(text->utils, "Unsafe SRP value for 'Av^u'\n"); 1650 r = SASL_BADPROT; 1651 goto err; 1652 } 1653 1654 /* K = H(S) */ 1655 r = MakeHash(text->md, K, Klen, "%m", &S); 1656 if (r) goto err; 1657 1658 r = SASL_OK; 1659 1660 err: 1661 BN_CTX_free(ctx); 1662 BN_clear_free(&u); 1663 BN_clear_free(&base); 1664 BN_clear_free(&S); 1665 1666 return r; 1667} 1668 1669static int ParseUserSecret(const sasl_utils_t *utils, 1670 char *secret, size_t seclen, 1671 char **mda, BIGNUM *v, char **salt, int *saltlen) 1672{ 1673 int r; 1674 1675 /* The secret data is stored as suggested in RFC 2945: 1676 * 1677 * { utf8(mda) mpi(v) os(salt) } (base64 encoded) 1678 */ 1679 r = utils->decode64(secret, seclen, secret, seclen, &seclen); 1680 1681 if (!r) 1682 r = UnBuffer(utils, secret, seclen, "%s%m%o", mda, v, saltlen, salt); 1683 if (r) { 1684 utils->seterror(utils->conn, 0, 1685 "Error UnBuffering user secret"); 1686 } 1687 1688 return r; 1689} 1690 1691static int CreateServerOptions(sasl_server_params_t *sparams, char **out) 1692{ 1693 srp_options_t opts; 1694 sasl_ssf_t limitssf, requiressf; 1695 layer_option_t *optlist; 1696 1697 /* zero out options */ 1698 memset(&opts,0,sizeof(srp_options_t)); 1699 1700 /* Add mda */ 1701 opts.mda = server_mda->bit; 1702 1703 if(sparams->props.maxbufsize == 0) { 1704 limitssf = 0; 1705 requiressf = 0; 1706 } else { 1707 if (sparams->props.max_ssf < sparams->external_ssf) { 1708 limitssf = 0; 1709 } else { 1710 limitssf = sparams->props.max_ssf - sparams->external_ssf; 1711 } 1712 if (sparams->props.min_ssf < sparams->external_ssf) { 1713 requiressf = 0; 1714 } else { 1715 requiressf = sparams->props.min_ssf - sparams->external_ssf; 1716 } 1717 } 1718 1719 /* 1720 * Add integrity options 1721 * Can't advertise integrity w/o support for default HMAC 1722 */ 1723 if (default_digest->enabled) { 1724 optlist = digest_options; 1725 while(optlist->name) { 1726 if (optlist->enabled && 1727 /*(requiressf <= 1) &&*/ (limitssf >= 1)) { 1728 opts.integrity |= optlist->bit; 1729 } 1730 optlist++; 1731 } 1732 } 1733 1734 /* if we set any integrity options we can advertise replay detection */ 1735 if (opts.integrity) { 1736 opts.replay_detection = 1; 1737 } 1738 1739 /* 1740 * Add confidentiality options 1741 * Can't advertise confidentiality w/o support for default cipher 1742 */ 1743 if (default_cipher->enabled) { 1744 optlist = cipher_options; 1745 while(optlist->name) { 1746 if (optlist->enabled && 1747 (requiressf <= optlist->ssf) && 1748 (limitssf >= optlist->ssf)) { 1749 opts.confidentiality |= optlist->bit; 1750 } 1751 optlist++; 1752 } 1753 } 1754 1755 /* Add mandatory options */ 1756 if (requiressf >= 1) 1757 opts.mandatory = BIT_REPLAY_DETECTION | BIT_INTEGRITY; 1758 if (requiressf > 1) 1759 opts.mandatory |= BIT_CONFIDENTIALITY; 1760 1761 /* Add maxbuffersize */ 1762 opts.maxbufsize = SRP_MAXBUFFERSIZE; 1763 if (sparams->props.maxbufsize && 1764 sparams->props.maxbufsize < opts.maxbufsize) 1765 opts.maxbufsize = sparams->props.maxbufsize; 1766 1767 return OptionsToString(sparams->utils, &opts, out); 1768} 1769 1770static int 1771srp_server_mech_new(void *glob_context __attribute__((unused)), 1772 sasl_server_params_t *params, 1773 const char *challenge __attribute__((unused)), 1774 unsigned challen __attribute__((unused)), 1775 void **conn_context) 1776{ 1777 context_t *text; 1778 1779 /* holds state are in */ 1780 text = params->utils->malloc(sizeof(context_t)); 1781 if (text == NULL) { 1782 MEMERROR(params->utils); 1783 return SASL_NOMEM; 1784 } 1785 1786 memset(text, 0, sizeof(context_t)); 1787 1788 text->state = 1; 1789 text->utils = params->utils; 1790 text->md = EVP_get_digestbyname(server_mda->evp_name); 1791 1792 *conn_context = text; 1793 1794 return SASL_OK; 1795} 1796 1797static int srp_server_mech_step1(context_t *text, 1798 sasl_server_params_t *params, 1799 const char *clientin, 1800 unsigned clientinlen, 1801 const char **serverout, 1802 unsigned *serveroutlen, 1803 sasl_out_params_t *oparams) 1804{ 1805 int result; 1806 char *sid = NULL; 1807 char *cn = NULL; 1808 int cnlen; 1809 char *realm = NULL; 1810 char *user = NULL; 1811 const char *password_request[] = { "*cmusaslsecretSRP", 1812 SASL_AUX_PASSWORD, 1813 NULL }; 1814 struct propval auxprop_values[3]; 1815 1816 /* Expect: 1817 * 1818 * U - authentication identity 1819 * I - authorization identity 1820 * sid - session id 1821 * cn - client nonce 1822 * 1823 * { utf8(U) utf8(I) utf8(sid) os(cn) } 1824 * 1825 */ 1826 result = UnBuffer(params->utils, clientin, clientinlen, 1827 "%s%s%s%o", &text->authid, &text->userid, &sid, 1828 &cnlen, &cn); 1829 if (result) { 1830 params->utils->seterror(params->utils->conn, 0, 1831 "Error UnBuffering input in step 1"); 1832 return result; 1833 } 1834 /* Get the realm */ 1835 result = _plug_parseuser(params->utils, &user, &realm, params->user_realm, 1836 params->serverFQDN, text->authid); 1837 if (result) { 1838 params->utils->seterror(params->utils->conn, 0, 1839 "Error getting realm"); 1840 goto cleanup; 1841 } 1842 1843 /* Generate N and g */ 1844 result = generate_N_and_g(&text->N, &text->g); 1845 if (result) { 1846 params->utils->seterror(text->utils->conn, 0, 1847 "Error calculating N and g"); 1848 return result; 1849 } 1850 1851 /* Get user secret */ 1852 result = params->utils->prop_request(params->propctx, password_request); 1853 if (result != SASL_OK) goto cleanup; 1854 1855 /* this will trigger the getting of the aux properties */ 1856 result = params->canon_user(params->utils->conn, 1857 text->authid, 0, SASL_CU_AUTHID, oparams); 1858 if (result != SASL_OK) goto cleanup; 1859 1860 result = params->canon_user(params->utils->conn, 1861 text->userid, 0, SASL_CU_AUTHZID, oparams); 1862 if (result != SASL_OK) goto cleanup; 1863 1864 result = params->utils->prop_getnames(params->propctx, password_request, 1865 auxprop_values); 1866 if (result < 0 || 1867 ((!auxprop_values[0].name || !auxprop_values[0].values) && 1868 (!auxprop_values[1].name || !auxprop_values[1].values))) { 1869 /* We didn't find this username */ 1870 params->utils->seterror(params->utils->conn,0, 1871 "no secret in database"); 1872 result = params->transition ? SASL_TRANS : SASL_NOUSER; 1873 goto cleanup; 1874 } 1875 1876 if (auxprop_values[0].name && auxprop_values[0].values) { 1877 char *mda = NULL; 1878 1879 /* We have a precomputed verifier */ 1880 result = ParseUserSecret(params->utils, 1881 (char*) auxprop_values[0].values[0], 1882 auxprop_values[0].valsize, 1883 &mda, &text->v, &text->salt, &text->saltlen); 1884 1885 if (result) { 1886 /* ParseUserSecret sets error, if any */ 1887 if (mda) params->utils->free(mda); 1888 goto cleanup; 1889 } 1890 1891 /* find mda */ 1892 server_mda = digest_options; 1893 while (server_mda->name) { 1894 if (!strcasecmp(server_mda->name, mda)) 1895 break; 1896 1897 server_mda++; 1898 } 1899 1900 if (!server_mda->name) { 1901 params->utils->seterror(params->utils->conn, 0, 1902 "unknown SRP mda '%s'", mda); 1903 params->utils->free(mda); 1904 result = SASL_FAIL; 1905 goto cleanup; 1906 } 1907 params->utils->free(mda); 1908 1909 } else if (auxprop_values[1].name && auxprop_values[1].values) { 1910 /* We only have the password -- calculate the verifier */ 1911 int len = strlen(auxprop_values[1].values[0]); 1912 1913 if (len == 0) { 1914 params->utils->seterror(params->utils->conn,0, 1915 "empty secret"); 1916 result = SASL_FAIL; 1917 goto cleanup; 1918 } 1919 1920 result = CalculateV(text, &text->N, &text->g, text->authid, 1921 auxprop_values[1].values[0], len, 1922 &text->v, &text->salt, &text->saltlen); 1923 if (result) { 1924 params->utils->seterror(params->utils->conn, 0, 1925 "Error calculating v"); 1926 goto cleanup; 1927 } 1928 } else { 1929 params->utils->seterror(params->utils->conn, 0, 1930 "Have neither type of secret"); 1931 result = SASL_FAIL; 1932 goto cleanup; 1933 } 1934 1935 /* erase the plaintext password */ 1936 params->utils->prop_erase(params->propctx, password_request[1]); 1937 1938 /* Calculate B */ 1939 result = CalculateB(text, &text->v, &text->N, &text->g, 1940 &text->b, &text->B); 1941 if (result) { 1942 params->utils->seterror(params->utils->conn, 0, 1943 "Error calculating B"); 1944 return result; 1945 } 1946 1947 /* Create L */ 1948 result = CreateServerOptions(params, &text->server_options); 1949 if (result) { 1950 params->utils->seterror(params->utils->conn, 0, 1951 "Error creating server options"); 1952 goto cleanup; 1953 } 1954 1955 /* Send out: 1956 * 1957 * N - safe prime modulus 1958 * g - generator 1959 * s - salt 1960 * B - server's public key 1961 * L - server options (available layers etc) 1962 * 1963 * { 0x00 mpi(N) mpi(g) os(s) mpi(B) utf8(L) } 1964 * 1965 */ 1966 result = MakeBuffer(text->utils, &text->out_buf, &text->out_buf_len, 1967 serveroutlen, "%c%m%m%o%m%s", 1968 0x00, &text->N, &text->g, text->saltlen, text->salt, 1969 &text->B, text->server_options); 1970 if (result) { 1971 params->utils->seterror(params->utils->conn, 0, 1972 "Error creating SRP buffer from data in step 1"); 1973 goto cleanup; 1974 } 1975 *serverout = text->out_buf; 1976 1977 text->state = 2; 1978 result = SASL_CONTINUE; 1979 1980 cleanup: 1981 if (sid) params->utils->free(sid); 1982 if (cn) params->utils->free(cn); 1983 if (user) params->utils->free(user); 1984 if (realm) params->utils->free(realm); 1985 1986 return result; 1987} 1988 1989static int srp_server_mech_step2(context_t *text, 1990 sasl_server_params_t *params, 1991 const char *clientin, 1992 unsigned clientinlen, 1993 const char **serverout, 1994 unsigned *serveroutlen, 1995 sasl_out_params_t *oparams) 1996{ 1997 int result; 1998 char *M1 = NULL, *cIV = NULL; /* don't free */ 1999 int M1len, cIVlen; 2000 srp_options_t client_opts; 2001 char myM1[EVP_MAX_MD_SIZE]; 2002 int myM1len; 2003 int i; 2004 char M2[EVP_MAX_MD_SIZE]; 2005 int M2len; 2006 char sIV[SRP_MAXBLOCKSIZE]; 2007 2008 /* Expect: 2009 * 2010 * A - client's public key 2011 * M1 - client evidence 2012 * o - client option list 2013 * cIV - client's initial vector 2014 * 2015 * { mpi(A) os(M1) utf8(o) os(cIV) } 2016 * 2017 */ 2018 result = UnBuffer(params->utils, clientin, clientinlen, 2019 "%m%-o%s%-o", &text->A, &M1len, &M1, 2020 &text->client_options, &cIVlen, &cIV); 2021 if (result) { 2022 params->utils->seterror(params->utils->conn, 0, 2023 "Error UnBuffering input in step 2"); 2024 goto cleanup; 2025 } 2026 2027 /* Per [SRP]: reject A <= 0 */ 2028 if (BigIntCmpWord(&text->A, 0) <= 0) { 2029 SETERROR(params->utils, "Illegal value for 'A'\n"); 2030 result = SASL_BADPROT; 2031 goto cleanup; 2032 } 2033 2034 /* parse client options */ 2035 result = ParseOptions(params->utils, text->client_options, &client_opts, 1); 2036 if (result) { 2037 params->utils->seterror(params->utils->conn, 0, 2038 "Error parsing user's options"); 2039 2040 if (client_opts.confidentiality) { 2041 /* Mark that we attempted confidentiality layer negotiation */ 2042 oparams->mech_ssf = 2; 2043 } 2044 else if (client_opts.integrity || client_opts.replay_detection) { 2045 /* Mark that we attempted integrity layer negotiation */ 2046 oparams->mech_ssf = 1; 2047 } 2048 return result; 2049 } 2050 2051 result = SetMDA(&client_opts, text); 2052 if (result) { 2053 params->utils->seterror(params->utils->conn, 0, 2054 "Error setting options"); 2055 return result; 2056 } 2057 2058 /* Calculate K */ 2059 result = ServerCalculateK(text, &text->v, &text->N, &text->A, 2060 &text->b, &text->B, text->K, &text->Klen); 2061 if (result) { 2062 params->utils->seterror(params->utils->conn, 0, 2063 "Error calculating K"); 2064 return result; 2065 } 2066 2067 /* See if M1 is correct */ 2068 result = CalculateM1(text, &text->N, &text->g, text->authid, 2069 text->salt, text->saltlen, &text->A, &text->B, 2070 text->K, text->Klen, text->userid, 2071 text->server_options, myM1, &myM1len); 2072 if (result) { 2073 params->utils->seterror(params->utils->conn, 0, 2074 "Error calculating M1"); 2075 goto cleanup; 2076 } 2077 2078 if (myM1len != M1len) { 2079 params->utils->seterror(params->utils->conn, 0, 2080 "SRP M1 lengths do not match"); 2081 result = SASL_BADAUTH; 2082 goto cleanup; 2083 } 2084 2085 for (i = 0; i < myM1len; i++) { 2086 if (myM1[i] != M1[i]) { 2087 params->utils->seterror(params->utils->conn, 0, 2088 "client evidence does not match what we " 2089 "calculated. Probably a password error"); 2090 result = SASL_BADAUTH; 2091 goto cleanup; 2092 } 2093 } 2094 2095 /* calculate M2 to send */ 2096 result = CalculateM2(text, &text->A, M1, M1len, text->K, text->Klen, 2097 text->userid, text->client_options, "", 0, 2098 M2, &M2len); 2099 if (result) { 2100 params->utils->seterror(params->utils->conn, 0, 2101 "Error calculating M2 (server evidence)"); 2102 goto cleanup; 2103 } 2104 2105 /* Create sIV (server initial vector) */ 2106 text->utils->rand(text->utils->rpool, sIV, sizeof(sIV)); 2107 2108 /* 2109 * Send out: 2110 * M2 - server evidence 2111 * sIV - server's initial vector 2112 * sid - session id 2113 * ttl - time to live 2114 * 2115 * { os(M2) os(sIV) utf8(sid) uint(ttl) } 2116 */ 2117 result = MakeBuffer(text->utils, &text->out_buf, &text->out_buf_len, 2118 serveroutlen, "%o%o%s%u", M2len, M2, 2119 sizeof(sIV), sIV, "", 0); 2120 if (result) { 2121 params->utils->seterror(params->utils->conn, 0, 2122 "Error making output buffer in SRP step 3"); 2123 goto cleanup; 2124 } 2125 *serverout = text->out_buf; 2126 2127 /* configure security layer */ 2128 result = LayerInit(&client_opts, text, oparams, cIV, sIV, 2129 params->props.maxbufsize); 2130 if (result) { 2131 params->utils->seterror(params->utils->conn, 0, 2132 "Error initializing security layer"); 2133 return result; 2134 } 2135 2136 /* set oparams */ 2137 oparams->doneflag = 1; 2138 oparams->param_version = 0; 2139 2140 result = SASL_OK; 2141 2142 cleanup: 2143 2144 return result; 2145} 2146 2147static int srp_server_mech_step(void *conn_context, 2148 sasl_server_params_t *sparams, 2149 const char *clientin, 2150 unsigned clientinlen, 2151 const char **serverout, 2152 unsigned *serveroutlen, 2153 sasl_out_params_t *oparams) 2154{ 2155 context_t *text = (context_t *) conn_context; 2156 2157 if (!sparams 2158 || !serverout 2159 || !serveroutlen 2160 || !oparams) 2161 return SASL_BADPARAM; 2162 2163 sparams->utils->log(NULL, SASL_LOG_DEBUG, 2164 "SRP server step %d\n", text->state); 2165 2166 *serverout = NULL; 2167 *serveroutlen = 0; 2168 2169 switch (text->state) { 2170 2171 case 1: 2172 return srp_server_mech_step1(text, sparams, clientin, clientinlen, 2173 serverout, serveroutlen, oparams); 2174 2175 case 2: 2176 return srp_server_mech_step2(text, sparams, clientin, clientinlen, 2177 serverout, serveroutlen, oparams); 2178 2179 default: 2180 sparams->utils->seterror(sparams->utils->conn, 0, 2181 "Invalid SRP server step %d", text->state); 2182 return SASL_FAIL; 2183 } 2184 2185 return SASL_FAIL; /* should never get here */ 2186} 2187 2188#ifdef DO_SRP_SETPASS 2189static int srp_setpass(void *glob_context __attribute__((unused)), 2190 sasl_server_params_t *sparams, 2191 const char *userstr, 2192 const char *pass, 2193 unsigned passlen __attribute__((unused)), 2194 const char *oldpass __attribute__((unused)), 2195 unsigned oldpasslen __attribute__((unused)), 2196 unsigned flags) 2197{ 2198 int r; 2199 char *user = NULL; 2200 char *user_only = NULL; 2201 char *realm = NULL; 2202 sasl_secret_t *sec = NULL; 2203 struct propctx *propctx = NULL; 2204 const char *store_request[] = { "cmusaslsecretSRP", 2205 NULL }; 2206 2207 /* Do we have a backend that can store properties? */ 2208 if (!sparams->utils->auxprop_store || 2209 sparams->utils->auxprop_store(NULL, NULL, NULL) != SASL_OK) { 2210 SETERROR(sparams->utils, "SRP: auxprop backend can't store properties"); 2211 return SASL_NOMECH; 2212 } 2213 2214 /* NB: Ideally we need to canonicalize userstr here */ 2215 r = _plug_parseuser(sparams->utils, &user_only, &realm, sparams->user_realm, 2216 sparams->serverFQDN, userstr); 2217 2218 if (r) { 2219 sparams->utils->seterror(sparams->utils->conn, 0, 2220 "Error parsing user"); 2221 return r; 2222 } 2223 2224 r = _plug_make_fulluser(sparams->utils, &user, user_only, realm); 2225 2226 if (r) { 2227 goto end; 2228 } 2229 2230 if ((flags & SASL_SET_DISABLE) || pass == NULL) { 2231 sec = NULL; 2232 } else { 2233 context_t *text; 2234 BIGNUM N; 2235 BIGNUM g; 2236 BIGNUM v; 2237 char *salt; 2238 int saltlen; 2239 char *buffer = NULL; 2240 int bufferlen, alloclen, encodelen; 2241 2242 text = sparams->utils->malloc(sizeof(context_t)); 2243 if (text == NULL) { 2244 MEMERROR(sparams->utils); 2245 return SASL_NOMEM; 2246 } 2247 2248 memset(text, 0, sizeof(context_t)); 2249 2250 text->utils = sparams->utils; 2251 text->md = EVP_get_digestbyname(server_mda->evp_name); 2252 2253 r = generate_N_and_g(&N, &g); 2254 if (r) { 2255 sparams->utils->seterror(sparams->utils->conn, 0, 2256 "Error calculating N and g"); 2257 goto end; 2258 } 2259 2260 /* user is a full username here */ 2261 r = CalculateV(text, &N, &g, user, pass, passlen, &v, &salt, &saltlen); 2262 if (r) { 2263 sparams->utils->seterror(sparams->utils->conn, 0, 2264 "Error calculating v"); 2265 goto end; 2266 } 2267 2268 /* The secret data is stored as suggested in RFC 2945: 2269 * 2270 * { utf8(mda) mpi(v) os(salt) } (base64 encoded) 2271 */ 2272 2273 r = MakeBuffer(text->utils, &text->out_buf, &text->out_buf_len, 2274 &bufferlen, "%s%m%o", 2275 server_mda->name, &v, saltlen, salt); 2276 2277 if (r) { 2278 sparams->utils->seterror(sparams->utils->conn, 0, 2279 "Error making buffer for secret"); 2280 goto end; 2281 } 2282 buffer = text->out_buf; 2283 2284 /* Put 'buffer' into sasl_secret_t. 2285 * This will be base64 encoded, so make sure its big enough. 2286 */ 2287 alloclen = (bufferlen/3 + 1) * 4 + 1; 2288 sec = sparams->utils->malloc(sizeof(sasl_secret_t)+alloclen); 2289 if (!sec) { 2290 r = SASL_NOMEM; 2291 goto end; 2292 } 2293 sparams->utils->encode64(buffer, bufferlen, sec->data, alloclen, 2294 &encodelen); 2295 sec->len = encodelen; 2296 2297 /* Clean everything up */ 2298 end: 2299 if (buffer) sparams->utils->free((void *) buffer); 2300 BN_clear_free(&N); 2301 BN_clear_free(&g); 2302 BN_clear_free(&v); 2303 sparams->utils->free(text); 2304 2305 if (r) return r; 2306 } 2307 2308 /* do the store */ 2309 propctx = sparams->utils->prop_new(0); 2310 if (!propctx) 2311 r = SASL_FAIL; 2312 if (!r) 2313 r = sparams->utils->prop_request(propctx, store_request); 2314 if (!r) 2315 r = sparams->utils->prop_set(propctx, "cmusaslsecretSRP", 2316 (sec ? sec->data : NULL), 2317 (sec ? sec->len : 0)); 2318 if (!r) 2319 r = sparams->utils->auxprop_store(sparams->utils->conn, propctx, user); 2320 if (propctx) 2321 sparams->utils->prop_dispose(&propctx); 2322 2323 if (r) { 2324 sparams->utils->seterror(sparams->utils->conn, 0, 2325 "Error putting SRP secret"); 2326 goto cleanup; 2327 } 2328 2329 sparams->utils->log(NULL, SASL_LOG_DEBUG, "Setpass for SRP successful\n"); 2330 2331 cleanup: 2332 2333 if (user) _plug_free_string(sparams->utils, &user); 2334 if (user_only) _plug_free_string(sparams->utils, &user_only); 2335 if (realm) _plug_free_string(sparams->utils, &realm); 2336 if (sec) _plug_free_secret(sparams->utils, &sec); 2337 2338 return r; 2339} 2340#endif /* DO_SRP_SETPASS */ 2341 2342static int srp_mech_avail(void *glob_context __attribute__((unused)), 2343 sasl_server_params_t *sparams, 2344 void **conn_context __attribute__((unused))) 2345{ 2346 /* Do we have access to the selected MDA? */ 2347 if (!server_mda || !server_mda->enabled) { 2348 SETERROR(sparams->utils, 2349 "SRP unavailable due to selected MDA unavailable"); 2350 return SASL_NOMECH; 2351 } 2352 2353 return SASL_OK; 2354} 2355 2356static sasl_server_plug_t srp_server_plugins[] = 2357{ 2358 { 2359 "SRP", /* mech_name */ 2360 0, /* max_ssf */ 2361 SASL_SEC_NOPLAINTEXT 2362 | SASL_SEC_NOANONYMOUS 2363 | SASL_SEC_NOACTIVE 2364 | SASL_SEC_NODICTIONARY 2365 | SASL_SEC_FORWARD_SECRECY 2366 | SASL_SEC_MUTUAL_AUTH, /* security_flags */ 2367 SASL_FEAT_WANT_CLIENT_FIRST 2368 | SASL_FEAT_ALLOWS_PROXY, /* features */ 2369 NULL, /* glob_context */ 2370 &srp_server_mech_new, /* mech_new */ 2371 &srp_server_mech_step, /* mech_step */ 2372 &srp_common_mech_dispose, /* mech_dispose */ 2373 &srp_common_mech_free, /* mech_free */ 2374#ifdef DO_SRP_SETPASS 2375 &srp_setpass, /* setpass */ 2376#else 2377 NULL, 2378#endif 2379 NULL, /* user_query */ 2380 NULL, /* idle */ 2381 &srp_mech_avail, /* mech avail */ 2382 NULL /* spare */ 2383 } 2384}; 2385 2386int srp_server_plug_init(const sasl_utils_t *utils, 2387 int maxversion, 2388 int *out_version, 2389 const sasl_server_plug_t **pluglist, 2390 int *plugcount, 2391 const char *plugname __attribute__((unused))) 2392{ 2393 const char *mda; 2394 unsigned int len; 2395 layer_option_t *opts; 2396 2397 if (maxversion < SASL_SERVER_PLUG_VERSION) { 2398 SETERROR(utils, "SRP version mismatch"); 2399 return SASL_BADVERS; 2400 } 2401 2402 utils->getopt(utils->getopt_context, "SRP", "srp_mda", &mda, &len); 2403 if (!mda) mda = DEFAULT_MDA; 2404 2405 /* Add all digests and ciphers */ 2406 OpenSSL_add_all_algorithms(); 2407 2408 /* See which digests we have available and set max_ssf accordingly */ 2409 opts = digest_options; 2410 while (opts->name) { 2411 if (EVP_get_digestbyname(opts->evp_name)) { 2412 opts->enabled = 1; 2413 2414 srp_server_plugins[0].max_ssf = opts->ssf; 2415 } 2416 2417 /* Locate the server MDA */ 2418 if (!strcasecmp(opts->name, mda) || !strcasecmp(opts->evp_name, mda)) { 2419 server_mda = opts; 2420 } 2421 2422 opts++; 2423 } 2424 2425 /* See which ciphers we have available and set max_ssf accordingly */ 2426 opts = cipher_options; 2427 while (opts->name) { 2428 if (EVP_get_cipherbyname(opts->evp_name)) { 2429 opts->enabled = 1; 2430 2431 if (opts->ssf > srp_server_plugins[0].max_ssf) { 2432 srp_server_plugins[0].max_ssf = opts->ssf; 2433 } 2434 } 2435 2436 opts++; 2437 } 2438 2439 *out_version = SASL_SERVER_PLUG_VERSION; 2440 *pluglist = srp_server_plugins; 2441 *plugcount = 1; 2442 2443 return SASL_OK; 2444} 2445 2446/***************************** Client Section *****************************/ 2447 2448/* Check to see if N,g is in the recommended list */ 2449static int check_N_and_g(const sasl_utils_t *utils, BIGNUM *N, BIGNUM *g) 2450{ 2451 char *N_prime; 2452 unsigned long g_prime; 2453 unsigned i; 2454 int r = SASL_FAIL; 2455 2456 N_prime = BN_bn2hex(N); 2457 g_prime = BN_get_word(g); 2458 2459 for (i = 0; i < NUM_Ng; i++) { 2460 if (!strcasecmp(N_prime, Ng_tab[i].N) && (g_prime == Ng_tab[i].g)) { 2461 r = SASL_OK; 2462 break; 2463 } 2464 } 2465 2466 if (N_prime) utils->free(N_prime); 2467 2468 return r; 2469} 2470 2471static int CalculateA(context_t *text __attribute__((unused)), 2472 BIGNUM *N, BIGNUM *g, BIGNUM *a, BIGNUM *A) 2473{ 2474 BN_CTX *ctx = BN_CTX_new(); 2475 2476 /* Generate a */ 2477 GetRandBigInt(a); 2478 2479 /* Per [SRP]: make sure a > log[g](N) -- g is always 2 */ 2480 BN_add_word(a, BN_num_bits(N)); 2481 2482 /* A = g^a % N */ 2483 BN_init(A); 2484 BN_mod_exp(A, g, a, N, ctx); 2485 2486 BN_CTX_free(ctx); 2487 2488 return SASL_OK; 2489} 2490 2491static int ClientCalculateK(context_t *text, char *salt, int saltlen, 2492 char *user, char *pass, int passlen, 2493 BIGNUM *N, BIGNUM *g, BIGNUM *a, BIGNUM *A, 2494 BIGNUM *B, char *K, int *Klen) 2495{ 2496 int r; 2497 unsigned char hash[EVP_MAX_MD_SIZE]; 2498 int hashlen; 2499 BIGNUM x; 2500 BIGNUM u; 2501 BIGNUM aux; 2502 BIGNUM gx; 2503 BIGNUM gx3; 2504 BIGNUM base; 2505 BIGNUM S; 2506 BN_CTX *ctx = BN_CTX_new(); 2507 2508 /* u = H(A | B) */ 2509 r = MakeHash(text->md, hash, &hashlen, "%m%m", A, B); 2510 if (r) goto err; 2511 BN_init(&u); 2512 BN_bin2bn(hash, hashlen, &u); 2513 2514 /* per Tom Wu: make sure u != 0 */ 2515 if (BN_is_zero(&u)) { 2516 SETERROR(text->utils, "SRP: Illegal value for 'u'\n"); 2517 r = SASL_BADPROT; 2518 goto err; 2519 } 2520 2521 /* S = (B - 3(g^x)) ^ (a + ux) % N */ 2522 2523 r = CalculateX(text, salt, saltlen, user, pass, passlen, &x); 2524 if (r) return r; 2525 2526 /* a + ux */ 2527 BN_init(&aux); 2528 BN_mul(&aux, &u, &x, ctx); 2529 BN_add(&aux, &aux, a); 2530 2531 /* gx3 = 3(g^x) % N */ 2532 BN_init(&gx); 2533 BN_mod_exp(&gx, g, &x, N, ctx); 2534 BN_init(&gx3); 2535 BN_set_word(&gx3, 3); 2536 BN_mod_mul(&gx3, &gx3, &gx, N, ctx); 2537 2538 /* base = (B - 3(g^x)) % N */ 2539 BN_init(&base); 2540#if OPENSSL_VERSION_NUMBER >= 0x00907000L 2541 BN_mod_sub(&base, B, &gx3, N, ctx); 2542#else 2543 BN_sub(&base, B, &gx3); 2544 BN_mod(&base, &base, N, ctx); 2545 if (BigIntCmpWord(&base, 0) < 0) { 2546 BN_add(&base, &base, N); 2547 } 2548#endif 2549 2550 /* S = base^aux % N */ 2551 BN_init(&S); 2552 BN_mod_exp(&S, &base, &aux, N, ctx); 2553 2554 /* K = H(S) */ 2555 r = MakeHash(text->md, K, Klen, "%m", &S); 2556 if (r) goto err; 2557 2558 r = SASL_OK; 2559 2560 err: 2561 BN_CTX_free(ctx); 2562 BN_clear_free(&x); 2563 BN_clear_free(&u); 2564 BN_clear_free(&aux); 2565 BN_clear_free(&gx); 2566 BN_clear_free(&gx3); 2567 BN_clear_free(&base); 2568 BN_clear_free(&S); 2569 2570 return r; 2571} 2572 2573static int CreateClientOpts(sasl_client_params_t *params, 2574 srp_options_t *available, 2575 srp_options_t *out) 2576{ 2577 layer_option_t *opt; 2578 sasl_ssf_t external; 2579 sasl_ssf_t limit; 2580 sasl_ssf_t musthave; 2581 2582 /* zero out output */ 2583 memset(out, 0, sizeof(srp_options_t)); 2584 2585 params->utils->log(NULL, SASL_LOG_DEBUG, 2586 "Available MDA = %d\n", available->mda); 2587 2588 /* mda */ 2589 opt = FindBest(available->mda, 0, 256, digest_options); 2590 2591 if (opt) { 2592 out->mda = opt->bit; 2593 } 2594 else { 2595 SETERROR(params->utils, "Can't find an acceptable SRP MDA\n"); 2596 return SASL_BADAUTH; 2597 } 2598 2599 /* get requested ssf */ 2600 external = params->external_ssf; 2601 2602 /* what do we _need_? how much is too much? */ 2603 if(params->props.maxbufsize == 0) { 2604 musthave = 0; 2605 limit = 0; 2606 } else { 2607 if (params->props.max_ssf > external) { 2608 limit = params->props.max_ssf - external; 2609 } else { 2610 limit = 0; 2611 } 2612 if (params->props.min_ssf > external) { 2613 musthave = params->props.min_ssf - external; 2614 } else { 2615 musthave = 0; 2616 } 2617 } 2618 2619 /* we now go searching for an option that gives us at least "musthave" 2620 and at most "limit" bits of ssf. */ 2621 params->utils->log(NULL, SASL_LOG_DEBUG, 2622 "Available confidentiality = %d " 2623 "musthave = %d limit = %d", 2624 available->confidentiality, musthave, limit); 2625 2626 /* confidentiality */ 2627 if (limit > 1) { 2628 2629 opt = FindBest(available->confidentiality, musthave, limit, 2630 cipher_options); 2631 2632 if (opt) { 2633 out->confidentiality = opt->bit; 2634 /* we've already satisfied the SSF with the confidentiality 2635 * layer, but we'll also use an integrity layer if we can 2636 */ 2637 musthave = 0; 2638 } 2639 else if (musthave > 1) { 2640 SETERROR(params->utils, 2641 "Can't find an acceptable SRP confidentiality layer\n"); 2642 return SASL_TOOWEAK; 2643 } 2644 } 2645 2646 params->utils->log(NULL, SASL_LOG_DEBUG, 2647 "Available integrity = %d " 2648 "musthave = %d limit = %d", 2649 available->integrity, musthave, limit); 2650 2651 /* integrity */ 2652 if ((limit >= 1) && (musthave <= 1)) { 2653 2654 opt = FindBest(available->integrity, musthave, limit, 2655 digest_options); 2656 2657 if (opt) { 2658 out->integrity = opt->bit; 2659 2660 /* if we set an integrity option we can set replay detection */ 2661 out->replay_detection = available->replay_detection; 2662 } 2663 else if (musthave > 0) { 2664 SETERROR(params->utils, 2665 "Can't find an acceptable SRP integrity layer\n"); 2666 return SASL_TOOWEAK; 2667 } 2668 } 2669 2670 /* Check to see if we've satisfied all of the servers mandatory layers */ 2671 params->utils->log(NULL, SASL_LOG_DEBUG, 2672 "Mandatory layers = %d\n",available->mandatory); 2673 2674 if ((!out->replay_detection && 2675 (available->mandatory & BIT_REPLAY_DETECTION)) || 2676 (!out->integrity && 2677 (available->mandatory & BIT_INTEGRITY)) || 2678 (!out->confidentiality && 2679 (available->mandatory & BIT_CONFIDENTIALITY))) { 2680 SETERROR(params->utils, "Mandatory SRP layer not supported\n"); 2681 return SASL_BADAUTH; 2682 } 2683 2684 /* Add maxbuffersize */ 2685 out->maxbufsize = SRP_MAXBUFFERSIZE; 2686 if (params->props.maxbufsize && params->props.maxbufsize < out->maxbufsize) 2687 out->maxbufsize = params->props.maxbufsize; 2688 2689 return SASL_OK; 2690} 2691 2692static int srp_client_mech_new(void *glob_context __attribute__((unused)), 2693 sasl_client_params_t *params, 2694 void **conn_context) 2695{ 2696 context_t *text; 2697 2698 /* holds state are in */ 2699 text = params->utils->malloc(sizeof(context_t)); 2700 if (text == NULL) { 2701 MEMERROR( params->utils ); 2702 return SASL_NOMEM; 2703 } 2704 2705 memset(text, 0, sizeof(context_t)); 2706 2707 text->state = 1; 2708 text->utils = params->utils; 2709 2710 *conn_context = text; 2711 2712 return SASL_OK; 2713} 2714 2715static int 2716srp_client_mech_step1(context_t *text, 2717 sasl_client_params_t *params, 2718 const char *serverin __attribute__((unused)), 2719 unsigned serverinlen, 2720 sasl_interact_t **prompt_need, 2721 const char **clientout, 2722 unsigned *clientoutlen, 2723 sasl_out_params_t *oparams) 2724{ 2725 const char *authid = NULL, *userid = NULL; 2726 int auth_result = SASL_OK; 2727 int pass_result = SASL_OK; 2728 int user_result = SASL_OK; 2729 int result; 2730 2731 /* Expect: 2732 * absolutely nothing 2733 * 2734 */ 2735 if (serverinlen > 0) { 2736 SETERROR(params->utils, "Invalid input to first step of SRP\n"); 2737 return SASL_BADPROT; 2738 } 2739 2740 /* try to get the authid */ 2741 if (oparams->authid==NULL) { 2742 auth_result = _plug_get_authid(params->utils, &authid, prompt_need); 2743 2744 if ((auth_result != SASL_OK) && (auth_result != SASL_INTERACT)) 2745 return auth_result; 2746 } 2747 2748 /* try to get the userid */ 2749 if (oparams->user == NULL) { 2750 user_result = _plug_get_userid(params->utils, &userid, prompt_need); 2751 2752 if ((user_result != SASL_OK) && (user_result != SASL_INTERACT)) 2753 return user_result; 2754 } 2755 2756 /* try to get the password */ 2757 if (text->password == NULL) { 2758 pass_result=_plug_get_password(params->utils, &text->password, 2759 &text->free_password, prompt_need); 2760 2761 if ((pass_result != SASL_OK) && (pass_result != SASL_INTERACT)) 2762 return pass_result; 2763 } 2764 2765 /* free prompts we got */ 2766 if (prompt_need && *prompt_need) { 2767 params->utils->free(*prompt_need); 2768 *prompt_need = NULL; 2769 } 2770 2771 /* if there are prompts not filled in */ 2772 if ((auth_result == SASL_INTERACT) || (user_result == SASL_INTERACT) || 2773 (pass_result == SASL_INTERACT)) { 2774 /* make the prompt list */ 2775 result = 2776 _plug_make_prompts(params->utils, prompt_need, 2777 user_result == SASL_INTERACT ? 2778 "Please enter your authorization name" : NULL, 2779 NULL, 2780 auth_result == SASL_INTERACT ? 2781 "Please enter your authentication name" : NULL, 2782 NULL, 2783 pass_result == SASL_INTERACT ? 2784 "Please enter your password" : NULL, NULL, 2785 NULL, NULL, NULL, 2786 NULL, NULL, NULL); 2787 if (result != SASL_OK) return result; 2788 2789 return SASL_INTERACT; 2790 } 2791 2792 if (!userid || !*userid) { 2793 result = params->canon_user(params->utils->conn, authid, 0, 2794 SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams); 2795 } 2796 else { 2797 result = params->canon_user(params->utils->conn, authid, 0, 2798 SASL_CU_AUTHID, oparams); 2799 if (result != SASL_OK) return result; 2800 2801 result = params->canon_user(params->utils->conn, userid, 0, 2802 SASL_CU_AUTHZID, oparams); 2803 } 2804 if (result != SASL_OK) return result; 2805 2806 /* Send out: 2807 * 2808 * U - authentication identity 2809 * I - authorization identity 2810 * sid - previous session id 2811 * cn - client nonce 2812 * 2813 * { utf8(U) utf8(I) utf8(sid) os(cn) } 2814 */ 2815 result = MakeBuffer(text->utils, &text->out_buf, &text->out_buf_len, 2816 clientoutlen, "%s%s%s%o", 2817 (char *) oparams->authid, (char *) oparams->user, 2818 "", 0, ""); 2819 if (result) { 2820 params->utils->log(NULL, SASL_LOG_ERR, "Error making output buffer\n"); 2821 goto cleanup; 2822 } 2823 *clientout = text->out_buf; 2824 2825 text->state = 2; 2826 2827 result = SASL_CONTINUE; 2828 2829 cleanup: 2830 2831 return result; 2832} 2833 2834static int 2835srp_client_mech_step2(context_t *text, 2836 sasl_client_params_t *params, 2837 const char *serverin, 2838 unsigned serverinlen, 2839 sasl_interact_t **prompt_need __attribute__((unused)), 2840 const char **clientout, 2841 unsigned *clientoutlen, 2842 sasl_out_params_t *oparams) 2843{ 2844 int result; 2845 char reuse; 2846 srp_options_t server_opts; 2847 2848 /* Expect: 2849 * 2850 * { 0x00 mpi(N) mpi(g) os(s) mpi(B) utf8(L) } 2851 */ 2852 result = UnBuffer(params->utils, serverin, serverinlen, 2853 "%c%m%m%o%m%s", &reuse, &text->N, &text->g, 2854 &text->saltlen, &text->salt, &text->B, 2855 &text->server_options); 2856 if (result) { 2857 params->utils->seterror(params->utils->conn, 0, 2858 "Error UnBuffering input in step 2"); 2859 goto cleanup; 2860 } 2861 2862 /* Check N and g to see if they are one of the recommended pairs */ 2863 result = check_N_and_g(params->utils, &text->N, &text->g); 2864 if (result) { 2865 params->utils->log(NULL, SASL_LOG_ERR, 2866 "Values of 'N' and 'g' are not recommended\n"); 2867 goto cleanup; 2868 } 2869 2870 /* Per [SRP]: reject B <= 0, B >= N */ 2871 if (BigIntCmpWord(&text->B, 0) <= 0 || BN_cmp(&text->B, &text->N) >= 0) { 2872 SETERROR(params->utils, "Illegal value for 'B'\n"); 2873 result = SASL_BADPROT; 2874 goto cleanup; 2875 } 2876 2877 /* parse server options */ 2878 memset(&server_opts, 0, sizeof(srp_options_t)); 2879 result = ParseOptions(params->utils, text->server_options, &server_opts, 0); 2880 if (result) { 2881 params->utils->log(NULL, SASL_LOG_ERR, 2882 "Error parsing SRP server options\n"); 2883 goto cleanup; 2884 } 2885 2886 /* Create o */ 2887 result = CreateClientOpts(params, &server_opts, &text->client_opts); 2888 if (result) { 2889 params->utils->log(NULL, SASL_LOG_ERR, 2890 "Error creating client options\n"); 2891 goto cleanup; 2892 } 2893 2894 result = OptionsToString(params->utils, &text->client_opts, 2895 &text->client_options); 2896 if (result) { 2897 params->utils->log(NULL, SASL_LOG_ERR, 2898 "Error converting client options to an option string\n"); 2899 goto cleanup; 2900 } 2901 2902 result = SetMDA(&text->client_opts, text); 2903 if (result) { 2904 params->utils->seterror(params->utils->conn, 0, 2905 "Error setting MDA"); 2906 goto cleanup; 2907 } 2908 2909 /* Calculate A */ 2910 result = CalculateA(text, &text->N, &text->g, &text->a, &text->A); 2911 if (result) { 2912 params->utils->seterror(params->utils->conn, 0, 2913 "Error calculating A"); 2914 return result; 2915 } 2916 2917 /* Calculate shared context key K */ 2918 result = ClientCalculateK(text, text->salt, text->saltlen, 2919 (char *) oparams->authid, 2920 text->password->data, text->password->len, 2921 &text->N, &text->g, &text->a, &text->A, &text->B, 2922 text->K, &text->Klen); 2923 if (result) { 2924 params->utils->log(NULL, SASL_LOG_ERR, 2925 "Error creating K\n"); 2926 goto cleanup; 2927 } 2928 2929 /* Calculate M1 (client evidence) */ 2930 result = CalculateM1(text, &text->N, &text->g, (char *) oparams->authid, 2931 text->salt, text->saltlen, &text->A, &text->B, 2932 text->K, text->Klen, (char *) oparams->user, 2933 text->server_options, text->M1, &text->M1len); 2934 if (result) { 2935 params->utils->log(NULL, SASL_LOG_ERR, 2936 "Error creating M1\n"); 2937 goto cleanup; 2938 } 2939 2940 /* Create cIV (client initial vector) */ 2941 text->utils->rand(text->utils->rpool, text->cIV, sizeof(text->cIV)); 2942 2943 /* Send out: 2944 * 2945 * A - client's public key 2946 * M1 - client evidence 2947 * o - client option list 2948 * cIV - client initial vector 2949 * 2950 * { mpi(A) os(M1) utf8(o) os(cIV) } 2951 */ 2952 result = MakeBuffer(text->utils, &text->out_buf, &text->out_buf_len, 2953 clientoutlen, "%m%o%s%o", 2954 &text->A, text->M1len, text->M1, text->client_options, 2955 sizeof(text->cIV), text->cIV); 2956 if (result) { 2957 params->utils->log(NULL, SASL_LOG_ERR, "Error making output buffer\n"); 2958 goto cleanup; 2959 } 2960 *clientout = text->out_buf; 2961 2962 text->state = 3; 2963 2964 result = SASL_CONTINUE; 2965 2966 cleanup: 2967 2968 return result; 2969} 2970 2971static int 2972srp_client_mech_step3(context_t *text, 2973 sasl_client_params_t *params, 2974 const char *serverin, 2975 unsigned serverinlen, 2976 sasl_interact_t **prompt_need __attribute__((unused)), 2977 const char **clientout __attribute__((unused)), 2978 unsigned *clientoutlen __attribute__((unused)), 2979 sasl_out_params_t *oparams) 2980{ 2981 int result; 2982 char *M2 = NULL, *sIV = NULL; /* don't free */ 2983 char *sid = NULL; 2984 int M2len, sIVlen; 2985 uint32 ttl; 2986 int i; 2987 char myM2[EVP_MAX_MD_SIZE]; 2988 int myM2len; 2989 2990 /* Expect: 2991 * 2992 * M2 - server evidence 2993 * sIV - server initial vector 2994 * sid - session id 2995 * ttl - time to live 2996 * 2997 * { os(M2) os(sIV) utf8(sid) uint(ttl) } 2998 */ 2999 result = UnBuffer(params->utils, serverin, serverinlen, 3000 "%-o%-o%s%u", &M2len, &M2, &sIVlen, &sIV, 3001 &sid, &ttl); 3002 if (result) { 3003 params->utils->seterror(params->utils->conn, 0, 3004 "Error UnBuffering input in step 3"); 3005 goto cleanup; 3006 } 3007 3008 /* calculate our own M2 */ 3009 result = CalculateM2(text, &text->A, text->M1, text->M1len, 3010 text->K, text->Klen, (char *) oparams->user, 3011 text->client_options, "", 0, 3012 myM2, &myM2len); 3013 if (result) { 3014 params->utils->log(NULL, SASL_LOG_ERR, 3015 "Error calculating our own M2 (server evidence)\n"); 3016 goto cleanup; 3017 } 3018 3019 /* compare to see if is server spoof */ 3020 if (myM2len != M2len) { 3021 SETERROR(params->utils, "SRP Server M2 length wrong\n"); 3022 result = SASL_BADSERV; 3023 goto cleanup; 3024 } 3025 3026 3027 for (i = 0; i < myM2len; i++) { 3028 if (M2[i] != myM2[i]) { 3029 SETERROR(params->utils, 3030 "SRP Server spoof detected. M2 incorrect\n"); 3031 result = SASL_BADSERV; 3032 goto cleanup; 3033 } 3034 } 3035 3036 /* 3037 * Send out: nothing 3038 */ 3039 3040 /* configure security layer */ 3041 result = LayerInit(&text->client_opts, text, oparams, sIV, text->cIV, 3042 params->props.maxbufsize); 3043 if (result) { 3044 params->utils->seterror(params->utils->conn, 0, 3045 "Error initializing security layer"); 3046 return result; 3047 } 3048 3049 /* set oparams */ 3050 oparams->doneflag = 1; 3051 oparams->param_version = 0; 3052 3053 result = SASL_OK; 3054 3055 cleanup: 3056 if (sid) params->utils->free(sid); 3057 3058 return result; 3059} 3060 3061static int srp_client_mech_step(void *conn_context, 3062 sasl_client_params_t *params, 3063 const char *serverin, 3064 unsigned serverinlen, 3065 sasl_interact_t **prompt_need, 3066 const char **clientout, 3067 unsigned *clientoutlen, 3068 sasl_out_params_t *oparams) 3069{ 3070 context_t *text = (context_t *) conn_context; 3071 3072 params->utils->log(NULL, SASL_LOG_DEBUG, 3073 "SRP client step %d\n", text->state); 3074 3075 *clientout = NULL; 3076 *clientoutlen = 0; 3077 3078 switch (text->state) { 3079 3080 case 1: 3081 return srp_client_mech_step1(text, params, serverin, serverinlen, 3082 prompt_need, clientout, clientoutlen, 3083 oparams); 3084 3085 case 2: 3086 return srp_client_mech_step2(text, params, serverin, serverinlen, 3087 prompt_need, clientout, clientoutlen, 3088 oparams); 3089 3090 case 3: 3091 return srp_client_mech_step3(text, params, serverin, serverinlen, 3092 prompt_need, clientout, clientoutlen, 3093 oparams); 3094 3095 default: 3096 params->utils->log(NULL, SASL_LOG_ERR, 3097 "Invalid SRP client step %d\n", text->state); 3098 return SASL_FAIL; 3099 } 3100 3101 return SASL_FAIL; /* should never get here */ 3102} 3103 3104 3105static sasl_client_plug_t srp_client_plugins[] = 3106{ 3107 { 3108 "SRP", /* mech_name */ 3109 0, /* max_ssf */ 3110 SASL_SEC_NOPLAINTEXT 3111 | SASL_SEC_NOANONYMOUS 3112 | SASL_SEC_NOACTIVE 3113 | SASL_SEC_NODICTIONARY 3114 | SASL_SEC_FORWARD_SECRECY 3115 | SASL_SEC_MUTUAL_AUTH, /* security_flags */ 3116 SASL_FEAT_WANT_CLIENT_FIRST 3117 | SASL_FEAT_ALLOWS_PROXY, /* features */ 3118 NULL, /* required_prompts */ 3119 NULL, /* glob_context */ 3120 &srp_client_mech_new, /* mech_new */ 3121 &srp_client_mech_step, /* mech_step */ 3122 &srp_common_mech_dispose, /* mech_dispose */ 3123 &srp_common_mech_free, /* mech_free */ 3124 NULL, /* idle */ 3125 NULL, /* spare */ 3126 NULL /* spare */ 3127 } 3128}; 3129 3130int srp_client_plug_init(const sasl_utils_t *utils __attribute__((unused)), 3131 int maxversion, 3132 int *out_version, 3133 const sasl_client_plug_t **pluglist, 3134 int *plugcount, 3135 const char *plugname __attribute__((unused))) 3136{ 3137 layer_option_t *opts; 3138 3139 if (maxversion < SASL_CLIENT_PLUG_VERSION) { 3140 SETERROR(utils, "SRP version mismatch"); 3141 return SASL_BADVERS; 3142 } 3143 3144 /* Add all digests and ciphers */ 3145 OpenSSL_add_all_algorithms(); 3146 3147 /* See which digests we have available and set max_ssf accordingly */ 3148 opts = digest_options; 3149 while (opts->name) { 3150 if (EVP_get_digestbyname(opts->evp_name)) { 3151 opts->enabled = 1; 3152 3153 srp_client_plugins[0].max_ssf = opts->ssf; 3154 } 3155 3156 opts++; 3157 } 3158 3159 /* See which ciphers we have available and set max_ssf accordingly */ 3160 opts = cipher_options; 3161 while (opts->name) { 3162 if (EVP_get_cipherbyname(opts->evp_name)) { 3163 opts->enabled = 1; 3164 3165 if (opts->ssf > srp_client_plugins[0].max_ssf) { 3166 srp_client_plugins[0].max_ssf = opts->ssf; 3167 } 3168 } 3169 3170 opts++; 3171 } 3172 3173 *out_version = SASL_CLIENT_PLUG_VERSION; 3174 *pluglist = srp_client_plugins; 3175 *plugcount=1; 3176 3177 return SASL_OK; 3178} 3179