4 * $Id: srp.c,v 1.58 2006/04/24 19:21:44 mel Exp $
7 * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
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
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
28 * Pittsburgh, PA 15213-3890
29 * (412) 268-4387, fax: (412) 268-7395
30 * tech-transfer@andrew.cmu.edu
32 * 4. Redistributions of any form whatsoever must retain the following
34 * "This product includes software developed by Computing Services
35 * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
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.
49 * - The authentication exchanges *should* be correct (per draft -08)
50 * but we won't know until we do some interop testing.
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
58 * - Are we using cIV and sIV correctly for encrypt/decrypt?
60 * - We don't implement fast reauth.
71 #define UINT32_MAX 4294967295U
74 #if UINT_MAX == UINT32_MAX
75 typedef unsigned int uint32;
76 #elif ULONG_MAX == UINT32_MAX
77 typedef unsigned long uint32;
78 #elif USHRT_MAX == UINT32_MAX
79 typedef unsigned short uint32;
81 #error dont know what to use for uint32
84 /* for big number support */
85 #include <openssl/bn.h>
87 /* for digest and cipher support */
88 #include <openssl/evp.h>
89 #include <openssl/hmac.h>
90 #include <openssl/md5.h>
93 #define MD5_H /* suppress internal MD5 */
96 #include "plugin_common.h"
99 #include <sasl_srp_plugin_decl.h>
102 /***************************** Common Section *****************************/
104 static const char plugin_id[] = "$Id: srp.c,v 1.58 2006/04/24 19:21:44 mel Exp $";
106 /* Size limit of cipher block size */
107 #define SRP_MAXBLOCKSIZE 16
108 /* Size limit of SRP buffer */
109 #define SRP_MAXBUFFERSIZE 2147483643
111 #define DEFAULT_MDA "SHA-1"
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="
120 /* Table of recommended Modulus (base 16) and Generator pairs */
126 { "115B8B692E0E045692CF280B436735C77A5A9E8A9E7ED56C965F87DB5B2A2ECE3",
130 { "8025363296FB943FCE54BE717E0E2958A02A9672EF561953B2BAA3BAACC3ED5754EB764C7AB7184578C57D5949CCB41B",
134 { "D4C7F8A2B32C11B8FBA9581EC4BA4F1B04215642EF7355E37C0FC0443EF756EA2C6B8EEB755A1C723027663CAA265EF785B8FF6A9B35227A52D86633DBDFCA43",
138 { "C94D67EB5B1A2346E8AB422FC6A0EDAEDA8C7F894C9EEEC42F9ED250FD7F0046E5AF2CF73D6B2FA26BB08033DA4DE322E144E7A8E9B12A0E4637F6371F34A2071C4B3836CBEEAB15034460FAA7ADF483",
142 { "B344C7C4F8C495031BB4E04FF8F84EE95008163940B9558276744D91F7CC9F402653BE7147F00F576B93754BCDDF71B636F2099E6FFF90E79575F3D0DE694AFF737D9BE9713CEF8D837ADA6380B1093E94B6A529A8C6C2BE33E0867C60C3262B",
146 { "EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE48E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B297BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9AFD5138FE8376435B9FC61D2FC0EB06E3",
150 { "D77946826E811914B39401D56A0A7843A8E7575D738C672A090AB1187D690DC43872FC06A7B6A43F3B95BEAEC7DF04B9D242EBDC481111283216CE816E004B786C5FCE856780D41837D95AD787A50BBE90BD3A9C98AC0F5FC0DE744B1CDE1891690894BC1F65E00DE15B4B2AA6D87100C9ECC2527E45EB849DEB14BB2049B163EA04187FD27C1BD9C7958CD40CE7067A9C024F9B7C5A0B4F5003686161F0605B",
154 { "9DEF3CAFB939277AB1F12A8617A47BBBDBA51DF499AC4C80BEEEA9614B19CC4D5F4F5F556E27CBDE51C6A94BE4607A291558903BA0D0F84380B655BB9A22E8DCDF028A7CEC67F0D08134B1C8B97989149B609E0BE3BAB63D47548381DBC5B1FC764E3F4B53DD9DA1158BFD3E2B9C8CF56EDF019539349627DB2FD53D24B7C48665772E437D6C7F8CE442734AF7CCB7AE837C264AE3A9BEB87F8A2FE9B8B5292E5A021FFF5E91479E8CE7A28C2442C6F315180F93499A234DCF76E3FED135F9BB",
158 { "AC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF6095179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF747359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A436C6481F1D2B9078717461A5B9D32E688F87748544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB694B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F9E4AFF73",
163 #define NUM_Ng (sizeof(Ng_tab) / sizeof(struct Ng))
166 typedef 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 */
174 static 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 }
180 static layer_option_t *default_digest = &digest_options[0];
181 static layer_option_t *server_mda = NULL;
183 static 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}
192 /* XXX Hack until OpenSSL 0.9.7 */
193 #if OPENSSL_VERSION_NUMBER < 0x00907000L
194 static layer_option_t *default_cipher = &cipher_options[0];
196 static layer_option_t *default_cipher = &cipher_options[2];
201 BIT_REPLAY_DETECTION= (1<<0),
202 BIT_INTEGRITY= (1<<1),
203 BIT_CONFIDENTIALITY= (1<<2)
206 typedef 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 */
215 /* The main SRP context */
216 typedef struct context {
219 BIGNUM N; /* safe prime modulus */
220 BIGNUM g; /* generator */
222 BIGNUM v; /* password verifier */
224 BIGNUM b; /* server private key */
225 BIGNUM B; /* server public key */
227 BIGNUM a; /* client private key */
228 BIGNUM A; /* client public key */
230 char K[EVP_MAX_MD_SIZE]; /* shared context key */
233 char M1[EVP_MAX_MD_SIZE]; /* client evidence */
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 */
241 char *client_options;
242 char *server_options;
244 srp_options_t client_opts; /* cache between client steps */
245 char cIV[SRP_MAXBLOCKSIZE]; /* cache between client steps */
247 char *salt; /* password salt */
250 const EVP_MD *md; /* underlying MDA */
252 /* copy of utils from the params structures */
253 const sasl_utils_t *utils;
255 /* per-step mem management */
257 unsigned out_buf_len;
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;
265 const EVP_CIPHER *cipher; /* cipher for confidentiality */
266 EVP_CIPHER_CTX cipher_enc_ctx;
267 EVP_CIPHER_CTX cipher_dec_ctx;
269 /* replay detection sequence numbers */
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;
277 /* layers buffering */
278 decode_context_t decode_context;
282 static int srp_encode(void *context,
283 const struct iovec *invec,
288 context_t *text = (context_t *) context;
291 unsigned long inputlen, tmpnum;
294 if (!context || !invec || !numiov || !output || !outputlen) {
295 PARAMERROR( text->utils );
296 return SASL_BADPARAM;
299 /* calculate total size of input */
300 for (i = 0, inputlen = 0; i < numiov; i++)
301 inputlen += invec[i].iov_len;
303 /* allocate a buffer for the output */
304 ret = _plug_buf_alloc(text->utils, &text->encode_buf,
305 &text->encode_buf_len,
307 inputlen + /* for content */
308 SRP_MAXBLOCKSIZE + /* for PKCS padding */
309 EVP_MAX_MD_SIZE); /* for HMAC */
310 if (ret != SASL_OK) return ret;
312 *outputlen = 4; /* length */
314 /* operate on each iovec */
315 for (i = 0; i < numiov; i++) {
316 input = invec[i].iov_base;
317 inputlen = invec[i].iov_len;
319 if (text->layer & BIT_CONFIDENTIALITY) {
322 /* encrypt the data into the output buffer */
323 EVP_EncryptUpdate(&text->cipher_enc_ctx,
324 text->encode_buf + *outputlen, &enclen,
326 *outputlen += enclen;
328 /* switch the input to the encrypted data */
329 input = text->encode_buf + 4;
330 inputlen = *outputlen - 4;
333 /* copy the raw input to the output */
334 memcpy(text->encode_buf + *outputlen, input, inputlen);
335 *outputlen += inputlen;
339 if (text->layer & BIT_CONFIDENTIALITY) {
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;
348 if (text->layer & BIT_INTEGRITY) {
351 /* hash the content */
352 HMAC_Update(&text->hmac_send_ctx, text->encode_buf+4, *outputlen-4);
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);
362 /* append the HMAC into the output buffer */
363 HMAC_Final(&text->hmac_send_ctx, text->encode_buf + *outputlen,
365 *outputlen += hashlen;
368 /* prepend the length of the output */
369 tmpnum = *outputlen - 4;
370 tmpnum = htonl(tmpnum);
371 memcpy(text->encode_buf, &tmpnum, 4);
373 *output = text->encode_buf;
378 /* decode a single SRP packet */
379 static int srp_decode_packet(void *context,
385 context_t *text = (context_t *) context;
388 if (text->layer & BIT_INTEGRITY) {
390 char myhash[EVP_MAX_MD_SIZE];
391 unsigned hashlen, myhashlen, i;
392 unsigned long tmpnum;
394 hashlen = EVP_MD_size(text->hmac_md);
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",
405 hash = input + inputlen;
407 /* create our own hash from the input */
408 HMAC_Update(&text->hmac_recv_ctx, input, inputlen);
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);
418 HMAC_Final(&text->hmac_recv_ctx, myhash, &myhashlen);
421 for (i = 0; i < hashlen; i++) {
422 if ((myhashlen != hashlen) || (myhash[i] != hash[i])) {
423 SETERROR(text->utils, "Hash is incorrect\n");
429 ret = _plug_buf_alloc(text->utils, &(text->decode_pkt_buf),
430 &(text->decode_pkt_buf_len),
432 if (ret != SASL_OK) return ret;
434 if (text->layer & BIT_CONFIDENTIALITY) {
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);
443 EVP_DecryptFinal(&text->cipher_dec_ctx,
444 text->decode_pkt_buf + declen, &declen);
445 *outputlen += declen;
447 /* copy the raw input to the output */
448 memcpy(text->decode_pkt_buf, input, inputlen);
449 *outputlen = inputlen;
452 *output = text->decode_pkt_buf;
457 /* decode and concatenate multiple SRP packets */
458 static int srp_decode(void *context,
459 const char *input, unsigned inputlen,
460 const char **output, unsigned *outputlen)
462 context_t *text = (context_t *) context;
465 ret = _plug_decode(&text->decode_context, input, inputlen,
466 &text->decode_buf, &text->decode_buf_len, outputlen,
467 srp_decode_packet, text);
469 *output = text->decode_buf;
475 * Convert a big integer to it's byte representation
477 static int BigIntToBytes(BIGNUM *num, char *out, int maxoutlen, int *outlen)
481 len = BN_num_bytes(num);
483 if (len > maxoutlen) return SASL_FAIL;
485 *outlen = BN_bn2bin(num, out);
491 * Compare a big integer against a word.
493 static int BigIntCmpWord(BIGNUM *a, BN_ULONG w)
495 BIGNUM *b = BN_new();
505 * Generate a random big integer.
507 static void GetRandBigInt(BIGNUM *out)
511 /* xxx likely should use sasl random funcs */
512 BN_rand(out, SRP_MAXBLOCKSIZE*8, 0, 0);
515 #define MAX_BUFFER_LEN 2147483643
516 #define MAX_MPI_LEN 65535
517 #define MAX_UTF8_LEN 65535
518 #define MAX_OS_LEN 255
521 * Make an SRP buffer from the data specified by the fmt string.
523 static int MakeBuffer(const sasl_utils_t *utils, char **buf, unsigned *buflen,
524 unsigned *outlen, const char *fmt, ...)
527 char *p, *out = NULL;
528 int r, alloclen, len;
535 /* first pass to calculate size of buffer */
537 for (p = (char *) fmt, alloclen = 0; *p; p++) {
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");
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");
567 os = va_arg(ap, char *);
572 str = va_arg(ap, char *);
574 if (len > MAX_UTF8_LEN) {
575 utils->log(NULL, SASL_LOG_ERR,
576 "String too long to create utf8 string\n");
585 u = va_arg(ap, uint32);
586 alloclen += sizeof(uint32);
591 c = va_arg(ap, int) & 0xFF;
602 if (alloclen > MAX_BUFFER_LEN) {
603 utils->log(NULL, SASL_LOG_ERR,
604 "String too long to create SRP buffer string\n");
609 r = _plug_buf_alloc(utils, buf, buflen, alloclen);
610 if (r != SASL_OK) return r;
612 out = *buf + 4; /* skip size for now */
614 /* second pass to fill buffer */
616 for (p = (char *) fmt; *p; p++) {
626 mpi = va_arg(ap, BIGNUM *);
627 r = BigIntToBytes(mpi, out+2, BN_num_bytes(mpi), &len);
630 memcpy(out, &ns, 2); /* add 2 byte len (network order) */
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 */
645 str = va_arg(ap, char *);
646 /* xxx do actual utf8 conversion */
649 memcpy(out, &ns, 2); /* add 2 byte len (network order) */
650 memcpy(out+2, str, len); /* add string */
656 u = va_arg(ap, uint32);
658 memcpy(out, &u, sizeof(uint32));
659 out += sizeof(uint32);
664 c = va_arg(ap, int) & 0xFF;
678 *outlen = out - *buf;
680 /* add 4 byte len (network order) */
681 totlen = htonl(*outlen - 4);
682 memcpy(*buf, &totlen, 4);
688 * Extract an SRP buffer into the data specified by the fmt string.
690 * A '-' flag means don't allocate memory for the data ('o' only).
692 static int UnBuffer(const sasl_utils_t *utils, const char *buf,
693 unsigned buflen, const char *fmt, ...)
697 int r = SASL_OK, noalloc;
704 if (!buf || buflen < 4) {
705 utils->seterror(utils->conn, 0,
706 "Buffer is not big enough to be SRP buffer: %d\n",
712 memcpy(&len, buf, 4);
717 /* make sure it's right */
719 SETERROR(utils, "SRP Buffer isn't of the right length\n");
724 for (p = (char *) fmt; *p; p++) {
735 /* check for noalloc flag */
736 if ((noalloc = (*++p == '-'))) ++p;
742 SETERROR(utils, "Buffer is not big enough to be SRP MPI\n");
753 /* make sure it's right */
755 SETERROR(utils, "Not enough data for this SRP MPI\n");
760 mpi = va_arg(ap, BIGNUM *);
762 BN_bin2bn(buf, len, mpi);
766 /* octet sequence (len followed by data) */
768 SETERROR(utils, "Buffer is not big enough to be SRP os\n");
774 len = (unsigned char) *buf;
778 /* make sure it's right */
780 SETERROR(utils, "Not enough data for this SRP os\n");
785 *(va_arg(ap, int *)) = len;
786 os = va_arg(ap, char **);
791 *os = (char *) utils->malloc(len);
797 memcpy(*os, buf, len);
804 SETERROR(utils, "Buffer is not big enough to be SRP UTF8\n");
815 /* make sure it's right */
817 SETERROR(utils, "Not enough data for this SRP UTF8\n");
822 str = va_arg(ap, char **);
823 *str = (char *) utils->malloc(len+1); /* +1 for NUL */
829 memcpy(*str, buf, len);
835 if (buflen < sizeof(uint32)) {
836 SETERROR(utils, "Buffer is not big enough to be SRP uint\n");
841 len = sizeof(uint32);
842 u = va_arg(ap, uint32*);
850 SETERROR(utils, "Buffer is not big enough to be SRP char\n");
856 *(va_arg(ap, char *)) = *buf;
876 SETERROR(utils, "Extra data in SRP buffer\n");
884 * Apply the hash function to the data specifed by the fmt string.
886 static int MakeHash(const EVP_MD *md, unsigned char hash[], int *hashlen,
887 const char *fmt, ...)
890 char *p, buf[4096], *in;
895 EVP_DigestInit(&mdctx, md);
898 for (p = (char *) fmt; *p; p++) {
905 if ((hflag = (*++p == 'h'))) ++p;
910 BIGNUM *mval = va_arg(ap, BIGNUM *);
913 r = BigIntToBytes(mval, buf, sizeof(buf)-1, &inlen);
919 /* octet sequence (len followed by data) */
920 inlen = va_arg(ap, int);
921 in = va_arg(ap, char *);
927 in = va_arg(ap, char *);
933 uint32 uval = va_arg(ap, uint32);
936 inlen = sizeof(uint32);
937 *((uint32 *) buf) = htonl(uval);
949 /* hash data separately before adding to current hash */
952 EVP_DigestInit(&tmpctx, md);
953 EVP_DigestUpdate(&tmpctx, in, inlen);
954 EVP_DigestFinal(&tmpctx, buf, &inlen);
958 EVP_DigestUpdate(&mdctx, in, inlen);
963 EVP_DigestFinal(&mdctx, hash, hashlen);
968 static int CalculateX(context_t *text, const char *salt, int saltlen,
969 const char *user, const char *pass, int passlen,
972 char hash[EVP_MAX_MD_SIZE];
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);
980 BN_bin2bn(hash, hashlen, x);
985 static 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)
991 unsigned char Nhash[EVP_MAX_MD_SIZE];
992 unsigned char ghash[EVP_MAX_MD_SIZE];
993 unsigned char Ng[EVP_MAX_MD_SIZE];
995 /* bytes(H( bytes(N) )) ^ bytes( H( bytes(g) ))
996 ^ is the bitwise XOR operator. */
997 r = MakeHash(text->md, Nhash, &len, "%m", N);
999 r = MakeHash(text->md, ghash, &len, "%m", g);
1002 for (i = 0; i < len; i++) {
1003 Ng[i] = (Nhash[i] ^ ghash[i]);
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);
1012 static 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)
1019 r = MakeHash(text->md, M2, M2len, "%m%o%o%hs%hs%s%u",
1020 A, M1len, M1, Klen, K, I, o, sid, ttl);
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
1029 static int ParseOption(const sasl_utils_t *utils,
1030 char *in, char **option, char **nextptr)
1036 if (strlen(in) == 0) {
1041 comma = strchr(in,',');
1042 if (comma == NULL) comma = in + strlen(in);
1046 *option = utils->malloc(len + 1);
1047 if (!*option) return SASL_NOMEM;
1049 /* lowercase string */
1050 for (i = 0; i < len; i++) {
1051 (*option)[i] = tolower((int)in[i]);
1053 (*option)[len] = '\0';
1064 static int FindBit(char *name, layer_option_t *opts)
1066 while (opts->name) {
1067 if (!strcasecmp(name, opts->name)) {
1077 static layer_option_t *FindOptionFromBit(unsigned bit, layer_option_t *opts)
1079 while (opts->name) {
1080 if (opts->bit == bit) {
1090 static int ParseOptionString(const sasl_utils_t *utils,
1091 char *str, srp_options_t *opts, int isserver)
1093 if (!strncasecmp(str, OPTION_MDA, strlen(OPTION_MDA))) {
1095 int bit = FindBit(str+strlen(OPTION_MDA), digest_options);
1097 if (isserver && (!bit || opts->mda)) {
1100 utils->seterror(utils->conn, 0,
1101 "SRP MDA %s not supported\n",
1102 str+strlen(OPTION_MDA));
1104 SETERROR(utils, "Multiple SRP MDAs given\n");
1105 return SASL_BADPROT;
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;
1115 opts->replay_detection = 1;
1117 } else if (!strncasecmp(str, OPTION_INTEGRITY, strlen(OPTION_INTEGRITY)) &&
1118 !strncasecmp(str+strlen(OPTION_INTEGRITY), "HMAC-", 5)) {
1120 int bit = FindBit(str+strlen(OPTION_INTEGRITY)+5, digest_options);
1122 if (isserver && (!bit || opts->integrity)) {
1123 opts->integrity = -1;
1125 utils->seterror(utils->conn, 0,
1126 "SRP Integrity option %s not supported\n",
1127 str+strlen(OPTION_INTEGRITY));
1129 SETERROR(utils, "Multiple SRP Integrity options given\n");
1130 return SASL_BADPROT;
1133 opts->integrity |= bit;
1135 } else if (!strncasecmp(str, OPTION_CONFIDENTIALITY,
1136 strlen(OPTION_CONFIDENTIALITY))) {
1138 int bit = FindBit(str+strlen(OPTION_CONFIDENTIALITY),
1141 if (isserver && (!bit || opts->confidentiality)) {
1142 opts->confidentiality = -1;
1144 utils->seterror(utils->conn, 0,
1145 "SRP Confidentiality option %s not supported\n",
1146 str+strlen(OPTION_CONFIDENTIALITY));
1149 "Multiple SRP Confidentiality options given\n");
1153 opts->confidentiality |= bit;
1155 } else if (!isserver && !strncasecmp(str, OPTION_MANDATORY,
1156 strlen(OPTION_MANDATORY))) {
1158 char *layer = str+strlen(OPTION_MANDATORY);
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;
1169 utils->seterror(utils->conn, 0,
1170 "Mandatory SRP option %s not supported\n", layer);
1171 return SASL_BADPROT;
1174 } else if (!strncasecmp(str, OPTION_MAXBUFFERSIZE,
1175 strlen(OPTION_MAXBUFFERSIZE))) {
1177 opts->maxbufsize = strtoul(str+strlen(OPTION_MAXBUFFERSIZE), NULL, 10);
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;
1187 /* Ignore unknown options */
1193 static int ParseOptions(const sasl_utils_t *utils,
1194 char *in, srp_options_t *out, int isserver)
1198 memset(out, 0, sizeof(srp_options_t));
1199 out->maxbufsize = SRP_MAXBUFFERSIZE;
1204 r = ParseOption(utils, in, &opt, &in);
1207 if (opt == NULL) return SASL_OK;
1209 utils->log(NULL, SASL_LOG_DEBUG, "Got option: [%s]\n",opt);
1211 r = ParseOptionString(utils, opt, out, isserver);
1220 static layer_option_t *FindBest(int available, sasl_ssf_t min_ssf,
1221 sasl_ssf_t max_ssf, layer_option_t *opts)
1223 layer_option_t *best = NULL;
1225 if (!available) return NULL;
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))) {
1240 static int OptionsToString(const sasl_utils_t *utils,
1241 srp_options_t *opts, char **out)
1246 layer_option_t *optlist;
1248 ret = utils->malloc(1);
1249 if (!ret) return SASL_NOMEM;
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;
1260 if (!first) strcat(ret, ",");
1261 strcat(ret, OPTION_MDA);
1262 strcat(ret, optlist->name);
1269 if (opts->replay_detection) {
1270 alloced += strlen(OPTION_REPLAY_DETECTION)+1;
1271 ret = utils->realloc(ret, alloced);
1272 if (!ret) return SASL_NOMEM;
1274 if (!first) strcat(ret, ",");
1275 strcat(ret, OPTION_REPLAY_DETECTION);
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;
1286 if (!first) strcat(ret, ",");
1287 strcat(ret, OPTION_INTEGRITY);
1288 strcat(ret, "HMAC-");
1289 strcat(ret, optlist->name);
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;
1303 if (!first) strcat(ret, ",");
1304 strcat(ret, OPTION_CONFIDENTIALITY);
1305 strcat(ret, optlist->name);
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;
1318 if (!first) strcat(ret, ",");
1319 strcat(ret, OPTION_MAXBUFFERSIZE);
1320 sprintf(ret+strlen(ret), "%lu", opts->maxbufsize);
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;
1329 if (!first) strcat(ret, ",");
1330 strcat(ret, OPTION_MANDATORY);
1331 strcat(ret, OPTION_REPLAY_DETECTION);
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;
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';
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;
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';
1367 * Set the selected MDA.
1369 static int SetMDA(srp_options_t *opts, context_t *text)
1371 layer_option_t *opt;
1373 opt = FindOptionFromBit(opts->mda, digest_options);
1375 text->utils->log(NULL, SASL_LOG_ERR,
1376 "Unable to find SRP MDA option now\n");
1380 text->md = EVP_get_digestbyname(opt->evp_name);
1386 * Setup the selected security layer.
1388 static int LayerInit(srp_options_t *opts, context_t *text,
1389 sasl_out_params_t *oparams, char *enc_IV, char *dec_IV,
1390 unsigned maxbufsize)
1392 layer_option_t *opt;
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");
1402 oparams->encode = &srp_encode;
1403 oparams->decode = &srp_decode;
1404 oparams->maxoutbuf = opts->maxbufsize - 4; /* account for 4-byte length */
1406 _plug_decode_init(&text->decode_context, text->utils, maxbufsize);
1408 if (opts->replay_detection) {
1409 text->utils->log(NULL, SASL_LOG_DEBUG, "Using replay detection\n");
1411 text->layer |= BIT_REPLAY_DETECTION;
1413 /* If no integrity layer specified, use default */
1414 if (!opts->integrity)
1415 opts->integrity = default_digest->bit;
1418 if (opts->integrity) {
1419 text->utils->log(NULL, SASL_LOG_DEBUG, "Using integrity protection\n");
1421 text->layer |= BIT_INTEGRITY;
1423 opt = FindOptionFromBit(opts->integrity, digest_options);
1425 text->utils->log(NULL, SASL_LOG_ERR,
1426 "Unable to find SRP integrity layer option\n");
1430 oparams->mech_ssf = opt->ssf;
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);
1437 /* account for HMAC */
1438 oparams->maxoutbuf -= EVP_MD_size(text->hmac_md);
1441 if (opts->confidentiality) {
1442 text->utils->log(NULL, SASL_LOG_DEBUG,
1443 "Using confidentiality protection\n");
1445 text->layer |= BIT_CONFIDENTIALITY;
1447 opt = FindOptionFromBit(opts->confidentiality, cipher_options);
1449 text->utils->log(NULL, SASL_LOG_ERR,
1450 "Unable to find SRP confidentiality layer option\n");
1454 oparams->mech_ssf = opt->ssf;
1456 /* Initialize the ciphers */
1457 text->cipher = EVP_get_cipherbyname(opt->evp_name);
1459 EVP_CIPHER_CTX_init(&text->cipher_enc_ctx);
1460 EVP_EncryptInit(&text->cipher_enc_ctx, text->cipher, text->K, enc_IV);
1462 EVP_CIPHER_CTX_init(&text->cipher_dec_ctx);
1463 EVP_DecryptInit(&text->cipher_dec_ctx, text->cipher, text->K, dec_IV);
1469 static void LayerCleanup(context_t *text)
1471 if (text->layer & BIT_INTEGRITY) {
1472 HMAC_cleanup(&text->hmac_send_ctx);
1473 HMAC_cleanup(&text->hmac_recv_ctx);
1476 if (text->layer & BIT_CONFIDENTIALITY) {
1477 EVP_CIPHER_CTX_cleanup(&text->cipher_enc_ctx);
1478 EVP_CIPHER_CTX_cleanup(&text->cipher_dec_ctx);
1484 * Dispose of a SRP context (could be server or client)
1486 static void srp_common_mech_dispose(void *conn_context,
1487 const sasl_utils_t *utils)
1489 context_t *text = (context_t *) conn_context;
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);
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);
1506 if (text->client_options) utils->free(text->client_options);
1507 if (text->server_options) utils->free(text->server_options);
1510 _plug_decode_free(&text->decode_context);
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);
1521 srp_common_mech_free(void *global_context __attribute__((unused)),
1522 const sasl_utils_t *utils __attribute__((unused)))
1528 /***************************** Server Section *****************************/
1530 /* A large safe prime (N = 2q+1, where q is prime)
1532 * Use N with the most bits from our table.
1534 * All arithmetic is done modulo N
1536 static int generate_N_and_g(BIGNUM *N, BIGNUM *g)
1541 result = BN_hex2bn(&N, Ng_tab[NUM_Ng-1].N);
1542 if (!result) return SASL_FAIL;
1545 BN_set_word(g, Ng_tab[NUM_Ng-1].g);
1550 static int CalculateV(context_t *text,
1551 BIGNUM *N, BIGNUM *g,
1553 const char *pass, unsigned passlen,
1554 BIGNUM *v, char **salt, int *saltlen)
1557 BN_CTX *ctx = BN_CTX_new();
1560 /* generate <salt> */
1561 *saltlen = SRP_MAXBLOCKSIZE;
1562 *salt = (char *)text->utils->malloc(*saltlen);
1563 if (!*salt) return SASL_NOMEM;
1564 text->utils->rand(text->utils->rpool, *salt, *saltlen);
1566 r = CalculateX(text, *salt, *saltlen, user, pass, passlen, &x);
1568 text->utils->seterror(text->utils->conn, 0,
1569 "Error calculating 'x'");
1575 BN_mod_exp(v, g, &x, N, ctx);
1583 static int CalculateB(context_t *text __attribute__((unused)),
1584 BIGNUM *v, BIGNUM *N, BIGNUM *g, BIGNUM *b, BIGNUM *B)
1587 BN_CTX *ctx = BN_CTX_new();
1592 /* Per [SRP]: make sure b > log[g](N) -- g is always 2 */
1593 BN_add_word(b, BN_num_bits(N));
1595 /* B = (3v + g^b) % N */
1597 BN_set_word(&v3, 3);
1598 BN_mod_mul(&v3, &v3, v, N, ctx);
1600 BN_mod_exp(B, g, b, N, ctx);
1601 #if OPENSSL_VERSION_NUMBER >= 0x00907000L
1602 BN_mod_add(B, B, &v3, N, ctx);
1605 BN_mod(B, B, N, ctx);
1613 static int ServerCalculateK(context_t *text, BIGNUM *v,
1614 BIGNUM *N, BIGNUM *A, BIGNUM *b, BIGNUM *B,
1617 unsigned char hash[EVP_MAX_MD_SIZE];
1622 BN_CTX *ctx = BN_CTX_new();
1626 r = MakeHash(text->md, hash, &hashlen, "%m%m", A, B);
1630 BN_bin2bn(hash, hashlen, &u);
1632 /* S = (Av^u) ^ b % N */
1634 BN_mod_exp(&base, v, &u, N, ctx);
1635 BN_mod_mul(&base, &base, A, N, ctx);
1638 BN_mod_exp(&S, &base, b, N, ctx);
1640 /* per Tom Wu: make sure Av^u != 1 (mod N) */
1641 if (BN_is_one(&base)) {
1642 SETERROR(text->utils, "Unsafe SRP value for 'Av^u'\n");
1647 /* per Tom Wu: make sure Av^u != -1 (mod N) */
1648 BN_add_word(&base, 1);
1649 if (BN_cmp(&S, N) == 0) {
1650 SETERROR(text->utils, "Unsafe SRP value for 'Av^u'\n");
1656 r = MakeHash(text->md, K, Klen, "%m", &S);
1664 BN_clear_free(&base);
1670 static int ParseUserSecret(const sasl_utils_t *utils,
1671 char *secret, size_t seclen,
1672 char **mda, BIGNUM *v, char **salt, int *saltlen)
1676 /* The secret data is stored as suggested in RFC 2945:
1678 * { utf8(mda) mpi(v) os(salt) } (base64 encoded)
1680 r = utils->decode64(secret, seclen, secret, seclen, &seclen);
1683 r = UnBuffer(utils, secret, seclen, "%s%m%o", mda, v, saltlen, salt);
1685 utils->seterror(utils->conn, 0,
1686 "Error UnBuffering user secret");
1692 static int CreateServerOptions(sasl_server_params_t *sparams, char **out)
1695 sasl_ssf_t limitssf, requiressf;
1696 layer_option_t *optlist;
1698 /* zero out options */
1699 memset(&opts,0,sizeof(srp_options_t));
1702 opts.mda = server_mda->bit;
1704 if(sparams->props.maxbufsize == 0) {
1708 if (sparams->props.max_ssf < sparams->external_ssf) {
1711 limitssf = sparams->props.max_ssf - sparams->external_ssf;
1713 if (sparams->props.min_ssf < sparams->external_ssf) {
1716 requiressf = sparams->props.min_ssf - sparams->external_ssf;
1721 * Add integrity options
1722 * Can't advertise integrity w/o support for default HMAC
1724 if (default_digest->enabled) {
1725 optlist = digest_options;
1726 while(optlist->name) {
1727 if (optlist->enabled &&
1728 /*(requiressf <= 1) &&*/ (limitssf >= 1)) {
1729 opts.integrity |= optlist->bit;
1735 /* if we set any integrity options we can advertise replay detection */
1736 if (opts.integrity) {
1737 opts.replay_detection = 1;
1741 * Add confidentiality options
1742 * Can't advertise confidentiality w/o support for default cipher
1744 if (default_cipher->enabled) {
1745 optlist = cipher_options;
1746 while(optlist->name) {
1747 if (optlist->enabled &&
1748 (requiressf <= optlist->ssf) &&
1749 (limitssf >= optlist->ssf)) {
1750 opts.confidentiality |= optlist->bit;
1756 /* Add mandatory options */
1757 if (requiressf >= 1)
1758 opts.mandatory = BIT_REPLAY_DETECTION | BIT_INTEGRITY;
1760 opts.mandatory |= BIT_CONFIDENTIALITY;
1762 /* Add maxbuffersize */
1763 opts.maxbufsize = SRP_MAXBUFFERSIZE;
1764 if (sparams->props.maxbufsize &&
1765 sparams->props.maxbufsize < opts.maxbufsize)
1766 opts.maxbufsize = sparams->props.maxbufsize;
1768 return OptionsToString(sparams->utils, &opts, out);
1772 srp_server_mech_new(void *glob_context __attribute__((unused)),
1773 sasl_server_params_t *params,
1774 const char *challenge __attribute__((unused)),
1775 unsigned challen __attribute__((unused)),
1776 void **conn_context)
1780 /* holds state are in */
1781 text = params->utils->malloc(sizeof(context_t));
1783 MEMERROR(params->utils);
1787 memset(text, 0, sizeof(context_t));
1790 text->utils = params->utils;
1791 text->md = EVP_get_digestbyname(server_mda->evp_name);
1793 *conn_context = text;
1798 static int srp_server_mech_step1(context_t *text,
1799 sasl_server_params_t *params,
1800 const char *clientin,
1801 unsigned clientinlen,
1802 const char **serverout,
1803 unsigned *serveroutlen,
1804 sasl_out_params_t *oparams)
1812 const char *password_request[] = { "*cmusaslsecretSRP",
1815 struct propval auxprop_values[3];
1819 * U - authentication identity
1820 * I - authorization identity
1824 * { utf8(U) utf8(I) utf8(sid) os(cn) }
1827 result = UnBuffer(params->utils, clientin, clientinlen,
1828 "%s%s%s%o", &text->authid, &text->userid, &sid,
1831 params->utils->seterror(params->utils->conn, 0,
1832 "Error UnBuffering input in step 1");
1836 result = _plug_parseuser(params->utils, &user, &realm, params->user_realm,
1837 params->serverFQDN, text->authid);
1839 params->utils->seterror(params->utils->conn, 0,
1840 "Error getting realm");
1844 /* Generate N and g */
1845 result = generate_N_and_g(&text->N, &text->g);
1847 params->utils->seterror(text->utils->conn, 0,
1848 "Error calculating N and g");
1852 /* Get user secret */
1853 result = params->utils->prop_request(params->propctx, password_request);
1854 if (result != SASL_OK) goto cleanup;
1856 /* this will trigger the getting of the aux properties */
1857 result = params->canon_user(params->utils->conn,
1858 text->authid, 0, SASL_CU_AUTHID, oparams);
1859 if (result != SASL_OK) goto cleanup;
1861 result = params->canon_user(params->utils->conn,
1862 text->userid, 0, SASL_CU_AUTHZID, oparams);
1863 if (result != SASL_OK) goto cleanup;
1865 result = params->utils->prop_getnames(params->propctx, password_request,
1868 ((!auxprop_values[0].name || !auxprop_values[0].values) &&
1869 (!auxprop_values[1].name || !auxprop_values[1].values))) {
1870 /* We didn't find this username */
1871 params->utils->seterror(params->utils->conn,0,
1872 "no secret in database");
1873 result = params->transition ? SASL_TRANS : SASL_NOUSER;
1877 if (auxprop_values[0].name && auxprop_values[0].values) {
1880 /* We have a precomputed verifier */
1881 result = ParseUserSecret(params->utils,
1882 (char*) auxprop_values[0].values[0],
1883 auxprop_values[0].valsize,
1884 &mda, &text->v, &text->salt, &text->saltlen);
1887 /* ParseUserSecret sets error, if any */
1888 if (mda) params->utils->free(mda);
1893 server_mda = digest_options;
1894 while (server_mda->name) {
1895 if (!strcasecmp(server_mda->name, mda))
1901 if (!server_mda->name) {
1902 params->utils->seterror(params->utils->conn, 0,
1903 "unknown SRP mda '%s'", mda);
1904 params->utils->free(mda);
1908 params->utils->free(mda);
1910 } else if (auxprop_values[1].name && auxprop_values[1].values) {
1911 /* We only have the password -- calculate the verifier */
1912 int len = strlen(auxprop_values[1].values[0]);
1915 params->utils->seterror(params->utils->conn,0,
1921 result = CalculateV(text, &text->N, &text->g, text->authid,
1922 auxprop_values[1].values[0], len,
1923 &text->v, &text->salt, &text->saltlen);
1925 params->utils->seterror(params->utils->conn, 0,
1926 "Error calculating v");
1930 params->utils->seterror(params->utils->conn, 0,
1931 "Have neither type of secret");
1936 /* erase the plaintext password */
1937 params->utils->prop_erase(params->propctx, password_request[1]);
1940 result = CalculateB(text, &text->v, &text->N, &text->g,
1941 &text->b, &text->B);
1943 params->utils->seterror(params->utils->conn, 0,
1944 "Error calculating B");
1949 result = CreateServerOptions(params, &text->server_options);
1951 params->utils->seterror(params->utils->conn, 0,
1952 "Error creating server options");
1958 * N - safe prime modulus
1961 * B - server's public key
1962 * L - server options (available layers etc)
1964 * { 0x00 mpi(N) mpi(g) os(s) mpi(B) utf8(L) }
1967 result = MakeBuffer(text->utils, &text->out_buf, &text->out_buf_len,
1968 serveroutlen, "%c%m%m%o%m%s",
1969 0x00, &text->N, &text->g, text->saltlen, text->salt,
1970 &text->B, text->server_options);
1972 params->utils->seterror(params->utils->conn, 0,
1973 "Error creating SRP buffer from data in step 1");
1976 *serverout = text->out_buf;
1979 result = SASL_CONTINUE;
1982 if (sid) params->utils->free(sid);
1983 if (cn) params->utils->free(cn);
1984 if (user) params->utils->free(user);
1985 if (realm) params->utils->free(realm);
1990 static int srp_server_mech_step2(context_t *text,
1991 sasl_server_params_t *params,
1992 const char *clientin,
1993 unsigned clientinlen,
1994 const char **serverout,
1995 unsigned *serveroutlen,
1996 sasl_out_params_t *oparams)
1999 char *M1 = NULL, *cIV = NULL; /* don't free */
2001 srp_options_t client_opts;
2002 char myM1[EVP_MAX_MD_SIZE];
2005 char M2[EVP_MAX_MD_SIZE];
2007 char sIV[SRP_MAXBLOCKSIZE];
2011 * A - client's public key
2012 * M1 - client evidence
2013 * o - client option list
2014 * cIV - client's initial vector
2016 * { mpi(A) os(M1) utf8(o) os(cIV) }
2019 result = UnBuffer(params->utils, clientin, clientinlen,
2020 "%m%-o%s%-o", &text->A, &M1len, &M1,
2021 &text->client_options, &cIVlen, &cIV);
2023 params->utils->seterror(params->utils->conn, 0,
2024 "Error UnBuffering input in step 2");
2028 /* Per [SRP]: reject A <= 0 */
2029 if (BigIntCmpWord(&text->A, 0) <= 0) {
2030 SETERROR(params->utils, "Illegal value for 'A'\n");
2031 result = SASL_BADPROT;
2035 /* parse client options */
2036 result = ParseOptions(params->utils, text->client_options, &client_opts, 1);
2038 params->utils->seterror(params->utils->conn, 0,
2039 "Error parsing user's options");
2041 if (client_opts.confidentiality) {
2042 /* Mark that we attempted confidentiality layer negotiation */
2043 oparams->mech_ssf = 2;
2045 else if (client_opts.integrity || client_opts.replay_detection) {
2046 /* Mark that we attempted integrity layer negotiation */
2047 oparams->mech_ssf = 1;
2052 result = SetMDA(&client_opts, text);
2054 params->utils->seterror(params->utils->conn, 0,
2055 "Error setting options");
2060 result = ServerCalculateK(text, &text->v, &text->N, &text->A,
2061 &text->b, &text->B, text->K, &text->Klen);
2063 params->utils->seterror(params->utils->conn, 0,
2064 "Error calculating K");
2068 /* See if M1 is correct */
2069 result = CalculateM1(text, &text->N, &text->g, text->authid,
2070 text->salt, text->saltlen, &text->A, &text->B,
2071 text->K, text->Klen, text->userid,
2072 text->server_options, myM1, &myM1len);
2074 params->utils->seterror(params->utils->conn, 0,
2075 "Error calculating M1");
2079 if (myM1len != M1len) {
2080 params->utils->seterror(params->utils->conn, 0,
2081 "SRP M1 lengths do not match");
2082 result = SASL_BADAUTH;
2086 for (i = 0; i < myM1len; i++) {
2087 if (myM1[i] != M1[i]) {
2088 params->utils->seterror(params->utils->conn, 0,
2089 "client evidence does not match what we "
2090 "calculated. Probably a password error");
2091 result = SASL_BADAUTH;
2096 /* calculate M2 to send */
2097 result = CalculateM2(text, &text->A, M1, M1len, text->K, text->Klen,
2098 text->userid, text->client_options, "", 0,
2101 params->utils->seterror(params->utils->conn, 0,
2102 "Error calculating M2 (server evidence)");
2106 /* Create sIV (server initial vector) */
2107 text->utils->rand(text->utils->rpool, sIV, sizeof(sIV));
2111 * M2 - server evidence
2112 * sIV - server's initial vector
2114 * ttl - time to live
2116 * { os(M2) os(sIV) utf8(sid) uint(ttl) }
2118 result = MakeBuffer(text->utils, &text->out_buf, &text->out_buf_len,
2119 serveroutlen, "%o%o%s%u", M2len, M2,
2120 sizeof(sIV), sIV, "", 0);
2122 params->utils->seterror(params->utils->conn, 0,
2123 "Error making output buffer in SRP step 3");
2126 *serverout = text->out_buf;
2128 /* configure security layer */
2129 result = LayerInit(&client_opts, text, oparams, cIV, sIV,
2130 params->props.maxbufsize);
2132 params->utils->seterror(params->utils->conn, 0,
2133 "Error initializing security layer");
2138 oparams->doneflag = 1;
2139 oparams->param_version = 0;
2148 static int srp_server_mech_step(void *conn_context,
2149 sasl_server_params_t *sparams,
2150 const char *clientin,
2151 unsigned clientinlen,
2152 const char **serverout,
2153 unsigned *serveroutlen,
2154 sasl_out_params_t *oparams)
2156 context_t *text = (context_t *) conn_context;
2162 return SASL_BADPARAM;
2164 sparams->utils->log(NULL, SASL_LOG_DEBUG,
2165 "SRP server step %d\n", text->state);
2170 switch (text->state) {
2173 return srp_server_mech_step1(text, sparams, clientin, clientinlen,
2174 serverout, serveroutlen, oparams);
2177 return srp_server_mech_step2(text, sparams, clientin, clientinlen,
2178 serverout, serveroutlen, oparams);
2181 sparams->utils->seterror(sparams->utils->conn, 0,
2182 "Invalid SRP server step %d", text->state);
2186 return SASL_FAIL; /* should never get here */
2189 #ifdef DO_SRP_SETPASS
2190 static int srp_setpass(void *glob_context __attribute__((unused)),
2191 sasl_server_params_t *sparams,
2192 const char *userstr,
2194 unsigned passlen __attribute__((unused)),
2195 const char *oldpass __attribute__((unused)),
2196 unsigned oldpasslen __attribute__((unused)),
2201 char *user_only = NULL;
2203 sasl_secret_t *sec = NULL;
2204 struct propctx *propctx = NULL;
2205 const char *store_request[] = { "cmusaslsecretSRP",
2208 /* Do we have a backend that can store properties? */
2209 if (!sparams->utils->auxprop_store ||
2210 sparams->utils->auxprop_store(NULL, NULL, NULL) != SASL_OK) {
2211 SETERROR(sparams->utils, "SRP: auxprop backend can't store properties");
2215 /* NB: Ideally we need to canonicalize userstr here */
2216 r = _plug_parseuser(sparams->utils, &user_only, &realm, sparams->user_realm,
2217 sparams->serverFQDN, userstr);
2220 sparams->utils->seterror(sparams->utils->conn, 0,
2221 "Error parsing user");
2225 r = _plug_make_fulluser(sparams->utils, &user, user_only, realm);
2231 if ((flags & SASL_SET_DISABLE) || pass == NULL) {
2240 char *buffer = NULL;
2241 int bufferlen, alloclen, encodelen;
2243 text = sparams->utils->malloc(sizeof(context_t));
2245 MEMERROR(sparams->utils);
2249 memset(text, 0, sizeof(context_t));
2251 text->utils = sparams->utils;
2252 text->md = EVP_get_digestbyname(server_mda->evp_name);
2254 r = generate_N_and_g(&N, &g);
2256 sparams->utils->seterror(sparams->utils->conn, 0,
2257 "Error calculating N and g");
2261 /* user is a full username here */
2262 r = CalculateV(text, &N, &g, user, pass, passlen, &v, &salt, &saltlen);
2264 sparams->utils->seterror(sparams->utils->conn, 0,
2265 "Error calculating v");
2269 /* The secret data is stored as suggested in RFC 2945:
2271 * { utf8(mda) mpi(v) os(salt) } (base64 encoded)
2274 r = MakeBuffer(text->utils, &text->out_buf, &text->out_buf_len,
2275 &bufferlen, "%s%m%o",
2276 server_mda->name, &v, saltlen, salt);
2279 sparams->utils->seterror(sparams->utils->conn, 0,
2280 "Error making buffer for secret");
2283 buffer = text->out_buf;
2285 /* Put 'buffer' into sasl_secret_t.
2286 * This will be base64 encoded, so make sure its big enough.
2288 alloclen = (bufferlen/3 + 1) * 4 + 1;
2289 sec = sparams->utils->malloc(sizeof(sasl_secret_t)+alloclen);
2294 sparams->utils->encode64(buffer, bufferlen, sec->data, alloclen,
2296 sec->len = encodelen;
2298 /* Clean everything up */
2300 if (buffer) sparams->utils->free((void *) buffer);
2304 sparams->utils->free(text);
2310 propctx = sparams->utils->prop_new(0);
2314 r = sparams->utils->prop_request(propctx, store_request);
2316 r = sparams->utils->prop_set(propctx, "cmusaslsecretSRP",
2317 (sec ? sec->data : NULL),
2318 (sec ? sec->len : 0));
2320 r = sparams->utils->auxprop_store(sparams->utils->conn, propctx, user);
2322 sparams->utils->prop_dispose(&propctx);
2325 sparams->utils->seterror(sparams->utils->conn, 0,
2326 "Error putting SRP secret");
2330 sparams->utils->log(NULL, SASL_LOG_DEBUG, "Setpass for SRP successful\n");
2334 if (user) _plug_free_string(sparams->utils, &user);
2335 if (user_only) _plug_free_string(sparams->utils, &user_only);
2336 if (realm) _plug_free_string(sparams->utils, &realm);
2337 if (sec) _plug_free_secret(sparams->utils, &sec);
2341 #endif /* DO_SRP_SETPASS */
2343 static int srp_mech_avail(void *glob_context __attribute__((unused)),
2344 sasl_server_params_t *sparams,
2345 void **conn_context __attribute__((unused)))
2347 /* Do we have access to the selected MDA? */
2348 if (!server_mda || !server_mda->enabled) {
2349 SETERROR(sparams->utils,
2350 "SRP unavailable due to selected MDA unavailable");
2357 static sasl_server_plug_t srp_server_plugins[] =
2360 "SRP", /* mech_name */
2362 SASL_SEC_NOPLAINTEXT
2363 | SASL_SEC_NOANONYMOUS
2365 | SASL_SEC_NODICTIONARY
2366 | SASL_SEC_FORWARD_SECRECY
2367 | SASL_SEC_MUTUAL_AUTH, /* security_flags */
2368 SASL_FEAT_WANT_CLIENT_FIRST
2369 | SASL_FEAT_ALLOWS_PROXY, /* features */
2370 NULL, /* glob_context */
2371 &srp_server_mech_new, /* mech_new */
2372 &srp_server_mech_step, /* mech_step */
2373 &srp_common_mech_dispose, /* mech_dispose */
2374 &srp_common_mech_free, /* mech_free */
2375 #ifdef DO_SRP_SETPASS
2376 &srp_setpass, /* setpass */
2380 NULL, /* user_query */
2382 &srp_mech_avail, /* mech avail */
2387 int srp_server_plug_init(const sasl_utils_t *utils,
2390 const sasl_server_plug_t **pluglist,
2392 const char *plugname __attribute__((unused)))
2396 layer_option_t *opts;
2398 if (maxversion < SASL_SERVER_PLUG_VERSION) {
2399 SETERROR(utils, "SRP version mismatch");
2400 return SASL_BADVERS;
2403 utils->getopt(utils->getopt_context, "SRP", "srp_mda", &mda, &len);
2404 if (!mda) mda = DEFAULT_MDA;
2406 /* Add all digests and ciphers */
2407 OpenSSL_add_all_algorithms();
2409 /* See which digests we have available and set max_ssf accordingly */
2410 opts = digest_options;
2411 while (opts->name) {
2412 if (EVP_get_digestbyname(opts->evp_name)) {
2415 srp_server_plugins[0].max_ssf = opts->ssf;
2418 /* Locate the server MDA */
2419 if (!strcasecmp(opts->name, mda) || !strcasecmp(opts->evp_name, mda)) {
2426 /* See which ciphers we have available and set max_ssf accordingly */
2427 opts = cipher_options;
2428 while (opts->name) {
2429 if (EVP_get_cipherbyname(opts->evp_name)) {
2432 if (opts->ssf > srp_server_plugins[0].max_ssf) {
2433 srp_server_plugins[0].max_ssf = opts->ssf;
2440 *out_version = SASL_SERVER_PLUG_VERSION;
2441 *pluglist = srp_server_plugins;
2447 /***************************** Client Section *****************************/
2449 /* Check to see if N,g is in the recommended list */
2450 static int check_N_and_g(const sasl_utils_t *utils, BIGNUM *N, BIGNUM *g)
2453 unsigned long g_prime;
2457 N_prime = BN_bn2hex(N);
2458 g_prime = BN_get_word(g);
2460 for (i = 0; i < NUM_Ng; i++) {
2461 if (!strcasecmp(N_prime, Ng_tab[i].N) && (g_prime == Ng_tab[i].g)) {
2467 if (N_prime) utils->free(N_prime);
2472 static int CalculateA(context_t *text __attribute__((unused)),
2473 BIGNUM *N, BIGNUM *g, BIGNUM *a, BIGNUM *A)
2475 BN_CTX *ctx = BN_CTX_new();
2480 /* Per [SRP]: make sure a > log[g](N) -- g is always 2 */
2481 BN_add_word(a, BN_num_bits(N));
2485 BN_mod_exp(A, g, a, N, ctx);
2492 static int ClientCalculateK(context_t *text, char *salt, int saltlen,
2493 char *user, char *pass, int passlen,
2494 BIGNUM *N, BIGNUM *g, BIGNUM *a, BIGNUM *A,
2495 BIGNUM *B, char *K, int *Klen)
2498 unsigned char hash[EVP_MAX_MD_SIZE];
2507 BN_CTX *ctx = BN_CTX_new();
2510 r = MakeHash(text->md, hash, &hashlen, "%m%m", A, B);
2513 BN_bin2bn(hash, hashlen, &u);
2515 /* per Tom Wu: make sure u != 0 */
2516 if (BN_is_zero(&u)) {
2517 SETERROR(text->utils, "SRP: Illegal value for 'u'\n");
2522 /* S = (B - 3(g^x)) ^ (a + ux) % N */
2524 r = CalculateX(text, salt, saltlen, user, pass, passlen, &x);
2529 BN_mul(&aux, &u, &x, ctx);
2530 BN_add(&aux, &aux, a);
2532 /* gx3 = 3(g^x) % N */
2534 BN_mod_exp(&gx, g, &x, N, ctx);
2536 BN_set_word(&gx3, 3);
2537 BN_mod_mul(&gx3, &gx3, &gx, N, ctx);
2539 /* base = (B - 3(g^x)) % N */
2541 #if OPENSSL_VERSION_NUMBER >= 0x00907000L
2542 BN_mod_sub(&base, B, &gx3, N, ctx);
2544 BN_sub(&base, B, &gx3);
2545 BN_mod(&base, &base, N, ctx);
2546 if (BigIntCmpWord(&base, 0) < 0) {
2547 BN_add(&base, &base, N);
2551 /* S = base^aux % N */
2553 BN_mod_exp(&S, &base, &aux, N, ctx);
2556 r = MakeHash(text->md, K, Klen, "%m", &S);
2565 BN_clear_free(&aux);
2567 BN_clear_free(&gx3);
2568 BN_clear_free(&base);
2574 static int CreateClientOpts(sasl_client_params_t *params,
2575 srp_options_t *available,
2578 layer_option_t *opt;
2579 sasl_ssf_t external;
2581 sasl_ssf_t musthave;
2583 /* zero out output */
2584 memset(out, 0, sizeof(srp_options_t));
2586 params->utils->log(NULL, SASL_LOG_DEBUG,
2587 "Available MDA = %d\n", available->mda);
2590 opt = FindBest(available->mda, 0, 256, digest_options);
2593 out->mda = opt->bit;
2596 SETERROR(params->utils, "Can't find an acceptable SRP MDA\n");
2597 return SASL_BADAUTH;
2600 /* get requested ssf */
2601 external = params->external_ssf;
2603 /* what do we _need_? how much is too much? */
2604 if(params->props.maxbufsize == 0) {
2608 if (params->props.max_ssf > external) {
2609 limit = params->props.max_ssf - external;
2613 if (params->props.min_ssf > external) {
2614 musthave = params->props.min_ssf - external;
2620 /* we now go searching for an option that gives us at least "musthave"
2621 and at most "limit" bits of ssf. */
2622 params->utils->log(NULL, SASL_LOG_DEBUG,
2623 "Available confidentiality = %d "
2624 "musthave = %d limit = %d",
2625 available->confidentiality, musthave, limit);
2627 /* confidentiality */
2630 opt = FindBest(available->confidentiality, musthave, limit,
2634 out->confidentiality = opt->bit;
2635 /* we've already satisfied the SSF with the confidentiality
2636 * layer, but we'll also use an integrity layer if we can
2640 else if (musthave > 1) {
2641 SETERROR(params->utils,
2642 "Can't find an acceptable SRP confidentiality layer\n");
2643 return SASL_TOOWEAK;
2647 params->utils->log(NULL, SASL_LOG_DEBUG,
2648 "Available integrity = %d "
2649 "musthave = %d limit = %d",
2650 available->integrity, musthave, limit);
2653 if ((limit >= 1) && (musthave <= 1)) {
2655 opt = FindBest(available->integrity, musthave, limit,
2659 out->integrity = opt->bit;
2661 /* if we set an integrity option we can set replay detection */
2662 out->replay_detection = available->replay_detection;
2664 else if (musthave > 0) {
2665 SETERROR(params->utils,
2666 "Can't find an acceptable SRP integrity layer\n");
2667 return SASL_TOOWEAK;
2671 /* Check to see if we've satisfied all of the servers mandatory layers */
2672 params->utils->log(NULL, SASL_LOG_DEBUG,
2673 "Mandatory layers = %d\n",available->mandatory);
2675 if ((!out->replay_detection &&
2676 (available->mandatory & BIT_REPLAY_DETECTION)) ||
2678 (available->mandatory & BIT_INTEGRITY)) ||
2679 (!out->confidentiality &&
2680 (available->mandatory & BIT_CONFIDENTIALITY))) {
2681 SETERROR(params->utils, "Mandatory SRP layer not supported\n");
2682 return SASL_BADAUTH;
2685 /* Add maxbuffersize */
2686 out->maxbufsize = SRP_MAXBUFFERSIZE;
2687 if (params->props.maxbufsize && params->props.maxbufsize < out->maxbufsize)
2688 out->maxbufsize = params->props.maxbufsize;
2693 static int srp_client_mech_new(void *glob_context __attribute__((unused)),
2694 sasl_client_params_t *params,
2695 void **conn_context)
2699 /* holds state are in */
2700 text = params->utils->malloc(sizeof(context_t));
2702 MEMERROR( params->utils );
2706 memset(text, 0, sizeof(context_t));
2709 text->utils = params->utils;
2711 *conn_context = text;
2717 srp_client_mech_step1(context_t *text,
2718 sasl_client_params_t *params,
2719 const char *serverin __attribute__((unused)),
2720 unsigned serverinlen,
2721 sasl_interact_t **prompt_need,
2722 const char **clientout,
2723 unsigned *clientoutlen,
2724 sasl_out_params_t *oparams)
2726 const char *authid = NULL, *userid = NULL;
2727 int auth_result = SASL_OK;
2728 int pass_result = SASL_OK;
2729 int user_result = SASL_OK;
2733 * absolutely nothing
2736 if (serverinlen > 0) {
2737 SETERROR(params->utils, "Invalid input to first step of SRP\n");
2738 return SASL_BADPROT;
2741 /* try to get the authid */
2742 if (oparams->authid==NULL) {
2743 auth_result = _plug_get_authid(params->utils, &authid, prompt_need);
2745 if ((auth_result != SASL_OK) && (auth_result != SASL_INTERACT))
2749 /* try to get the userid */
2750 if (oparams->user == NULL) {
2751 user_result = _plug_get_userid(params->utils, &userid, prompt_need);
2753 if ((user_result != SASL_OK) && (user_result != SASL_INTERACT))
2757 /* try to get the password */
2758 if (text->password == NULL) {
2759 pass_result=_plug_get_password(params->utils, &text->password,
2760 &text->free_password, prompt_need);
2762 if ((pass_result != SASL_OK) && (pass_result != SASL_INTERACT))
2766 /* free prompts we got */
2767 if (prompt_need && *prompt_need) {
2768 params->utils->free(*prompt_need);
2769 *prompt_need = NULL;
2772 /* if there are prompts not filled in */
2773 if ((auth_result == SASL_INTERACT) || (user_result == SASL_INTERACT) ||
2774 (pass_result == SASL_INTERACT)) {
2775 /* make the prompt list */
2777 _plug_make_prompts(params->utils, prompt_need,
2778 user_result == SASL_INTERACT ?
2779 "Please enter your authorization name" : NULL,
2781 auth_result == SASL_INTERACT ?
2782 "Please enter your authentication name" : NULL,
2784 pass_result == SASL_INTERACT ?
2785 "Please enter your password" : NULL, NULL,
2788 if (result != SASL_OK) return result;
2790 return SASL_INTERACT;
2793 if (!userid || !*userid) {
2794 result = params->canon_user(params->utils->conn, authid, 0,
2795 SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams);
2798 result = params->canon_user(params->utils->conn, authid, 0,
2799 SASL_CU_AUTHID, oparams);
2800 if (result != SASL_OK) return result;
2802 result = params->canon_user(params->utils->conn, userid, 0,
2803 SASL_CU_AUTHZID, oparams);
2805 if (result != SASL_OK) return result;
2809 * U - authentication identity
2810 * I - authorization identity
2811 * sid - previous session id
2814 * { utf8(U) utf8(I) utf8(sid) os(cn) }
2816 result = MakeBuffer(text->utils, &text->out_buf, &text->out_buf_len,
2817 clientoutlen, "%s%s%s%o",
2818 (char *) oparams->authid, (char *) oparams->user,
2821 params->utils->log(NULL, SASL_LOG_ERR, "Error making output buffer\n");
2824 *clientout = text->out_buf;
2828 result = SASL_CONTINUE;
2836 srp_client_mech_step2(context_t *text,
2837 sasl_client_params_t *params,
2838 const char *serverin,
2839 unsigned serverinlen,
2840 sasl_interact_t **prompt_need __attribute__((unused)),
2841 const char **clientout,
2842 unsigned *clientoutlen,
2843 sasl_out_params_t *oparams)
2847 srp_options_t server_opts;
2851 * { 0x00 mpi(N) mpi(g) os(s) mpi(B) utf8(L) }
2853 result = UnBuffer(params->utils, serverin, serverinlen,
2854 "%c%m%m%o%m%s", &reuse, &text->N, &text->g,
2855 &text->saltlen, &text->salt, &text->B,
2856 &text->server_options);
2858 params->utils->seterror(params->utils->conn, 0,
2859 "Error UnBuffering input in step 2");
2863 /* Check N and g to see if they are one of the recommended pairs */
2864 result = check_N_and_g(params->utils, &text->N, &text->g);
2866 params->utils->log(NULL, SASL_LOG_ERR,
2867 "Values of 'N' and 'g' are not recommended\n");
2871 /* Per [SRP]: reject B <= 0, B >= N */
2872 if (BigIntCmpWord(&text->B, 0) <= 0 || BN_cmp(&text->B, &text->N) >= 0) {
2873 SETERROR(params->utils, "Illegal value for 'B'\n");
2874 result = SASL_BADPROT;
2878 /* parse server options */
2879 memset(&server_opts, 0, sizeof(srp_options_t));
2880 result = ParseOptions(params->utils, text->server_options, &server_opts, 0);
2882 params->utils->log(NULL, SASL_LOG_ERR,
2883 "Error parsing SRP server options\n");
2888 result = CreateClientOpts(params, &server_opts, &text->client_opts);
2890 params->utils->log(NULL, SASL_LOG_ERR,
2891 "Error creating client options\n");
2895 result = OptionsToString(params->utils, &text->client_opts,
2896 &text->client_options);
2898 params->utils->log(NULL, SASL_LOG_ERR,
2899 "Error converting client options to an option string\n");
2903 result = SetMDA(&text->client_opts, text);
2905 params->utils->seterror(params->utils->conn, 0,
2906 "Error setting MDA");
2911 result = CalculateA(text, &text->N, &text->g, &text->a, &text->A);
2913 params->utils->seterror(params->utils->conn, 0,
2914 "Error calculating A");
2918 /* Calculate shared context key K */
2919 result = ClientCalculateK(text, text->salt, text->saltlen,
2920 (char *) oparams->authid,
2921 text->password->data, text->password->len,
2922 &text->N, &text->g, &text->a, &text->A, &text->B,
2923 text->K, &text->Klen);
2925 params->utils->log(NULL, SASL_LOG_ERR,
2926 "Error creating K\n");
2930 /* Calculate M1 (client evidence) */
2931 result = CalculateM1(text, &text->N, &text->g, (char *) oparams->authid,
2932 text->salt, text->saltlen, &text->A, &text->B,
2933 text->K, text->Klen, (char *) oparams->user,
2934 text->server_options, text->M1, &text->M1len);
2936 params->utils->log(NULL, SASL_LOG_ERR,
2937 "Error creating M1\n");
2941 /* Create cIV (client initial vector) */
2942 text->utils->rand(text->utils->rpool, text->cIV, sizeof(text->cIV));
2946 * A - client's public key
2947 * M1 - client evidence
2948 * o - client option list
2949 * cIV - client initial vector
2951 * { mpi(A) os(M1) utf8(o) os(cIV) }
2953 result = MakeBuffer(text->utils, &text->out_buf, &text->out_buf_len,
2954 clientoutlen, "%m%o%s%o",
2955 &text->A, text->M1len, text->M1, text->client_options,
2956 sizeof(text->cIV), text->cIV);
2958 params->utils->log(NULL, SASL_LOG_ERR, "Error making output buffer\n");
2961 *clientout = text->out_buf;
2965 result = SASL_CONTINUE;
2973 srp_client_mech_step3(context_t *text,
2974 sasl_client_params_t *params,
2975 const char *serverin,
2976 unsigned serverinlen,
2977 sasl_interact_t **prompt_need __attribute__((unused)),
2978 const char **clientout __attribute__((unused)),
2979 unsigned *clientoutlen __attribute__((unused)),
2980 sasl_out_params_t *oparams)
2983 char *M2 = NULL, *sIV = NULL; /* don't free */
2988 char myM2[EVP_MAX_MD_SIZE];
2993 * M2 - server evidence
2994 * sIV - server initial vector
2996 * ttl - time to live
2998 * { os(M2) os(sIV) utf8(sid) uint(ttl) }
3000 result = UnBuffer(params->utils, serverin, serverinlen,
3001 "%-o%-o%s%u", &M2len, &M2, &sIVlen, &sIV,
3004 params->utils->seterror(params->utils->conn, 0,
3005 "Error UnBuffering input in step 3");
3009 /* calculate our own M2 */
3010 result = CalculateM2(text, &text->A, text->M1, text->M1len,
3011 text->K, text->Klen, (char *) oparams->user,
3012 text->client_options, "", 0,
3015 params->utils->log(NULL, SASL_LOG_ERR,
3016 "Error calculating our own M2 (server evidence)\n");
3020 /* compare to see if is server spoof */
3021 if (myM2len != M2len) {
3022 SETERROR(params->utils, "SRP Server M2 length wrong\n");
3023 result = SASL_BADSERV;
3028 for (i = 0; i < myM2len; i++) {
3029 if (M2[i] != myM2[i]) {
3030 SETERROR(params->utils,
3031 "SRP Server spoof detected. M2 incorrect\n");
3032 result = SASL_BADSERV;
3041 /* configure security layer */
3042 result = LayerInit(&text->client_opts, text, oparams, sIV, text->cIV,
3043 params->props.maxbufsize);
3045 params->utils->seterror(params->utils->conn, 0,
3046 "Error initializing security layer");
3051 oparams->doneflag = 1;
3052 oparams->param_version = 0;
3057 if (sid) params->utils->free(sid);
3062 static int srp_client_mech_step(void *conn_context,
3063 sasl_client_params_t *params,
3064 const char *serverin,
3065 unsigned serverinlen,
3066 sasl_interact_t **prompt_need,
3067 const char **clientout,
3068 unsigned *clientoutlen,
3069 sasl_out_params_t *oparams)
3071 context_t *text = (context_t *) conn_context;
3073 params->utils->log(NULL, SASL_LOG_DEBUG,
3074 "SRP client step %d\n", text->state);
3079 switch (text->state) {
3082 return srp_client_mech_step1(text, params, serverin, serverinlen,
3083 prompt_need, clientout, clientoutlen,
3087 return srp_client_mech_step2(text, params, serverin, serverinlen,
3088 prompt_need, clientout, clientoutlen,
3092 return srp_client_mech_step3(text, params, serverin, serverinlen,
3093 prompt_need, clientout, clientoutlen,
3097 params->utils->log(NULL, SASL_LOG_ERR,
3098 "Invalid SRP client step %d\n", text->state);
3102 return SASL_FAIL; /* should never get here */
3106 static sasl_client_plug_t srp_client_plugins[] =
3109 "SRP", /* mech_name */
3111 SASL_SEC_NOPLAINTEXT
3112 | SASL_SEC_NOANONYMOUS
3114 | SASL_SEC_NODICTIONARY
3115 | SASL_SEC_FORWARD_SECRECY
3116 | SASL_SEC_MUTUAL_AUTH, /* security_flags */
3117 SASL_FEAT_WANT_CLIENT_FIRST
3118 | SASL_FEAT_ALLOWS_PROXY, /* features */
3119 NULL, /* required_prompts */
3120 NULL, /* glob_context */
3121 &srp_client_mech_new, /* mech_new */
3122 &srp_client_mech_step, /* mech_step */
3123 &srp_common_mech_dispose, /* mech_dispose */
3124 &srp_common_mech_free, /* mech_free */
3131 int srp_client_plug_init(const sasl_utils_t *utils __attribute__((unused)),
3134 const sasl_client_plug_t **pluglist,
3136 const char *plugname __attribute__((unused)))
3138 layer_option_t *opts;
3140 if (maxversion < SASL_CLIENT_PLUG_VERSION) {
3141 SETERROR(utils, "SRP version mismatch");
3142 return SASL_BADVERS;
3145 /* Add all digests and ciphers */
3146 OpenSSL_add_all_algorithms();
3148 /* See which digests we have available and set max_ssf accordingly */
3149 opts = digest_options;
3150 while (opts->name) {
3151 if (EVP_get_digestbyname(opts->evp_name)) {
3154 srp_client_plugins[0].max_ssf = opts->ssf;
3160 /* See which ciphers we have available and set max_ssf accordingly */
3161 opts = cipher_options;
3162 while (opts->name) {
3163 if (EVP_get_cipherbyname(opts->evp_name)) {
3166 if (opts->ssf > srp_client_plugins[0].max_ssf) {
3167 srp_client_plugins[0].max_ssf = opts->ssf;
3174 *out_version = SASL_CLIENT_PLUG_VERSION;
3175 *pluglist = srp_client_plugins;