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