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