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