GSS_S_PROMPTING_NEEDED is a bit
[cyrus-sasl.git] / plugins / srp.c
1 /* SRP SASL plugin
2  * Ken Murchison
3  * Tim Martin  3/17/00
4  * $Id: srp.c,v 1.58 2006/04/24 19:21:44 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
75 typedef unsigned int uint32;
76 #elif ULONG_MAX == UINT32_MAX
77 typedef unsigned long uint32;
78 #elif USHRT_MAX == UINT32_MAX
79 typedef unsigned short uint32;
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
104 static const char plugin_id[] = "$Id: srp.c,v 1.58 2006/04/24 19:21:44 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 */
121 struct 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
166 typedef struct layer_option_s {
167     const char *name;           /* name used in option strings */
168     unsigned enabled;           /* enabled?  determined at run-time */
169     unsigned bit;               /* unique bit in bitmask */
170     sasl_ssf_t ssf;             /* ssf of layer */
171     const char *evp_name;       /* name used for lookup in EVP table */
172 } layer_option_t;
173
174 static layer_option_t digest_options[] = {
175     { "SHA-1",          0, (1<<0), 1,   "sha1" },
176     { "RIPEMD-160",     0, (1<<1), 1,   "rmd160" },
177     { "MD5",            0, (1<<2), 1,   "md5" },
178     { NULL,             0,      0, 0,   NULL }
179 };
180 static layer_option_t *default_digest = &digest_options[0];
181 static layer_option_t *server_mda = NULL;
182
183 static layer_option_t cipher_options[] = {
184     { "DES",            0, (1<<0), 56,  "des-ofb" },
185     { "3DES",           0, (1<<1), 112, "des-ede-ofb" },
186     { "AES",            0, (1<<2), 128, "aes-128-ofb" },
187     { "Blowfish",       0, (1<<3), 128, "bf-ofb" },
188     { "CAST-128",       0, (1<<4), 128, "cast5-ofb" },
189     { "IDEA",           0, (1<<5), 128, "idea-ofb" },
190     { NULL,             0,      0, 0,   NULL}
191 };
192 /* XXX Hack until OpenSSL 0.9.7 */
193 #if OPENSSL_VERSION_NUMBER < 0x00907000L
194 static layer_option_t *default_cipher = &cipher_options[0];
195 #else
196 static layer_option_t *default_cipher = &cipher_options[2];
197 #endif
198
199
200 enum {
201     BIT_REPLAY_DETECTION=       (1<<0),
202     BIT_INTEGRITY=              (1<<1),
203     BIT_CONFIDENTIALITY=        (1<<2)
204 };
205
206 typedef struct srp_options_s {
207     unsigned mda;               /* bitmask of MDAs */
208     unsigned replay_detection;  /* replay detection on/off flag */
209     unsigned integrity;         /* bitmask of integrity layers */
210     unsigned confidentiality;   /* bitmask of confidentiality layers */
211     unsigned mandatory;         /* bitmask of mandatory layers */
212     unsigned long maxbufsize;   /* max # bytes processed by security layer */
213 } srp_options_t;
214
215 /* The main SRP context */
216 typedef 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
282 static 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 */
379 static 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 */
458 static 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  */
477 static 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  */
493 static 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  */
507 static 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  */
523 static 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  */
692 static 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  */
886 static 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
968 static 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
985 static int CalculateM1(context_t *text, BIGNUM *N, BIGNUM *g,
986                        char *U, char *salt, int saltlen,
987                        BIGNUM *A, BIGNUM *B, char *K, int Klen,
988                        char *I, char *L, char *M1, int *M1len)
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
1012 static int CalculateM2(context_t *text, BIGNUM *A,
1013                        char *M1, int M1len, char *K, int Klen,
1014                        char *I, char *o, char *sid, uint32 ttl,
1015                        char *M2, int *M2len)
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  */
1029 static 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
1064 static 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
1077 static 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
1090 static 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
1193 static 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
1220 static 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
1240 static 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  */
1369 static 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  */
1388 static int LayerInit(srp_options_t *opts, context_t *text,
1389                      sasl_out_params_t *oparams, char *enc_IV, char *dec_IV,
1390                      unsigned maxbufsize)
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
1469 static 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  */ 
1486 static 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
1520 static void
1521 srp_common_mech_free(void *global_context __attribute__((unused)),
1522                      const sasl_utils_t *utils __attribute__((unused)))
1523 {
1524     EVP_cleanup();
1525 }
1526
1527
1528 /*****************************  Server Section  *****************************/
1529
1530 /* A large safe prime (N = 2q+1, where q is prime)
1531  *
1532  * Use N with the most bits from our table.
1533  *
1534  * All arithmetic is done modulo N
1535  */
1536 static int generate_N_and_g(BIGNUM *N, BIGNUM *g)
1537 {
1538     int result;
1539     
1540     BN_init(N);
1541     result = BN_hex2bn(&N, Ng_tab[NUM_Ng-1].N);
1542     if (!result) return SASL_FAIL;
1543     
1544     BN_init(g);
1545     BN_set_word(g, Ng_tab[NUM_Ng-1].g);
1546     
1547     return SASL_OK;
1548 }
1549
1550 static int CalculateV(context_t *text,
1551                       BIGNUM *N, BIGNUM *g,
1552                       const char *user,
1553                       const char *pass, unsigned passlen,
1554                       BIGNUM *v, char **salt, int *saltlen)
1555 {
1556     BIGNUM x;
1557     BN_CTX *ctx = BN_CTX_new();
1558     int r;
1559     
1560     /* generate <salt> */    
1561     *saltlen = SRP_MAXBLOCKSIZE;
1562     *salt = (char *)text->utils->malloc(*saltlen);
1563     if (!*salt) return SASL_NOMEM;
1564     text->utils->rand(text->utils->rpool, *salt, *saltlen);
1565     
1566     r = CalculateX(text, *salt, *saltlen, user, pass, passlen, &x);
1567     if (r) {
1568         text->utils->seterror(text->utils->conn, 0, 
1569                               "Error calculating 'x'");
1570         return r;
1571     }
1572     
1573     /* v = g^x % N */
1574     BN_init(v);
1575     BN_mod_exp(v, g, &x, N, ctx);
1576     
1577     BN_CTX_free(ctx);
1578     BN_clear_free(&x);
1579     
1580     return r;   
1581 }
1582
1583 static int CalculateB(context_t *text  __attribute__((unused)),
1584                       BIGNUM *v, BIGNUM *N, BIGNUM *g, BIGNUM *b, BIGNUM *B)
1585 {
1586     BIGNUM v3;
1587     BN_CTX *ctx = BN_CTX_new();
1588     
1589     /* Generate b */
1590     GetRandBigInt(b);
1591         
1592     /* Per [SRP]: make sure b > log[g](N) -- g is always 2 */
1593     BN_add_word(b, BN_num_bits(N));
1594         
1595     /* B = (3v + g^b) % N */
1596     BN_init(&v3);
1597     BN_set_word(&v3, 3);
1598     BN_mod_mul(&v3, &v3, v, N, ctx);
1599     BN_init(B);
1600     BN_mod_exp(B, g, b, N, ctx);
1601 #if OPENSSL_VERSION_NUMBER >= 0x00907000L
1602     BN_mod_add(B, B, &v3, N, ctx);
1603 #else
1604     BN_add(B, B, &v3);
1605     BN_mod(B, B, N, ctx);
1606 #endif
1607
1608     BN_CTX_free(ctx);
1609     
1610     return SASL_OK;
1611 }
1612         
1613 static int ServerCalculateK(context_t *text, BIGNUM *v,
1614                             BIGNUM *N, BIGNUM *A, BIGNUM *b, BIGNUM *B,
1615                             char *K, int *Klen)
1616 {
1617     unsigned char hash[EVP_MAX_MD_SIZE];
1618     int hashlen;
1619     BIGNUM u;
1620     BIGNUM base;
1621     BIGNUM S;
1622     BN_CTX *ctx = BN_CTX_new();
1623     int r;
1624     
1625     /* u = H(A | B) */
1626     r = MakeHash(text->md, hash, &hashlen, "%m%m", A, B);
1627     if (r) return r;
1628         
1629     BN_init(&u);
1630     BN_bin2bn(hash, hashlen, &u);
1631         
1632     /* S = (Av^u) ^ b % N */
1633     BN_init(&base);
1634     BN_mod_exp(&base, v, &u, N, ctx);
1635     BN_mod_mul(&base, &base, A, N, ctx);
1636     
1637     BN_init(&S);
1638     BN_mod_exp(&S, &base, b, N, ctx);
1639     
1640     /* per Tom Wu: make sure Av^u != 1 (mod N) */
1641     if (BN_is_one(&base)) {
1642         SETERROR(text->utils, "Unsafe SRP value for 'Av^u'\n");
1643         r = SASL_BADPROT;
1644         goto err;
1645     }
1646     
1647     /* per Tom Wu: make sure Av^u != -1 (mod N) */
1648     BN_add_word(&base, 1);
1649     if (BN_cmp(&S, N) == 0) {
1650         SETERROR(text->utils, "Unsafe SRP value for 'Av^u'\n");
1651         r = SASL_BADPROT;
1652         goto err;
1653     }
1654     
1655     /* K = H(S) */
1656     r = MakeHash(text->md, K, Klen, "%m", &S);
1657     if (r) goto err;
1658     
1659     r = SASL_OK;
1660     
1661   err:
1662     BN_CTX_free(ctx);
1663     BN_clear_free(&u);
1664     BN_clear_free(&base);
1665     BN_clear_free(&S);
1666     
1667     return r;
1668 }
1669
1670 static int ParseUserSecret(const sasl_utils_t *utils,
1671                            char *secret, size_t seclen,
1672                            char **mda, BIGNUM *v, char **salt, int *saltlen)
1673 {
1674     int r;
1675     
1676     /* The secret data is stored as suggested in RFC 2945:
1677      *
1678      *  { utf8(mda) mpi(v) os(salt) }  (base64 encoded)
1679      */
1680     r = utils->decode64(secret, seclen, secret, seclen, &seclen);
1681
1682     if (!r)
1683         r = UnBuffer(utils, secret, seclen, "%s%m%o", mda, v, saltlen, salt);
1684     if (r) {
1685         utils->seterror(utils->conn, 0, 
1686                         "Error UnBuffering user secret");
1687     }
1688
1689     return r;
1690 }
1691
1692 static int CreateServerOptions(sasl_server_params_t *sparams, char **out)
1693 {
1694     srp_options_t opts;
1695     sasl_ssf_t limitssf, requiressf;
1696     layer_option_t *optlist;
1697     
1698     /* zero out options */
1699     memset(&opts,0,sizeof(srp_options_t));
1700     
1701     /* Add mda */
1702     opts.mda = server_mda->bit;
1703
1704     if(sparams->props.maxbufsize == 0) {
1705         limitssf = 0;
1706         requiressf = 0;
1707     } else {
1708         if (sparams->props.max_ssf < sparams->external_ssf) {
1709             limitssf = 0;
1710         } else {
1711             limitssf = sparams->props.max_ssf - sparams->external_ssf;
1712         }
1713         if (sparams->props.min_ssf < sparams->external_ssf) {
1714             requiressf = 0;
1715         } else {
1716             requiressf = sparams->props.min_ssf - sparams->external_ssf;
1717         }
1718     }
1719     
1720     /*
1721      * Add integrity options
1722      * Can't advertise integrity w/o support for default HMAC
1723      */
1724     if (default_digest->enabled) {
1725         optlist = digest_options;
1726         while(optlist->name) {
1727             if (optlist->enabled &&
1728                 /*(requiressf <= 1) &&*/ (limitssf >= 1)) {
1729                 opts.integrity |= optlist->bit;
1730             }
1731             optlist++;
1732         }
1733     }
1734     
1735     /* if we set any integrity options we can advertise replay detection */
1736     if (opts.integrity) {
1737         opts.replay_detection = 1;
1738     }
1739     
1740     /*
1741      * Add confidentiality options
1742      * Can't advertise confidentiality w/o support for default cipher
1743      */
1744     if (default_cipher->enabled) {
1745         optlist = cipher_options;
1746         while(optlist->name) {
1747             if (optlist->enabled &&
1748                 (requiressf <= optlist->ssf) &&
1749                 (limitssf >= optlist->ssf)) {
1750                 opts.confidentiality |= optlist->bit;
1751             }
1752             optlist++;
1753         }
1754     }
1755     
1756     /* Add mandatory options */
1757     if (requiressf >= 1)
1758         opts.mandatory = BIT_REPLAY_DETECTION | BIT_INTEGRITY;
1759     if (requiressf > 1)
1760         opts.mandatory |= BIT_CONFIDENTIALITY;
1761     
1762     /* Add maxbuffersize */
1763     opts.maxbufsize = SRP_MAXBUFFERSIZE;
1764     if (sparams->props.maxbufsize &&
1765         sparams->props.maxbufsize < opts.maxbufsize)
1766         opts.maxbufsize = sparams->props.maxbufsize;
1767     
1768     return OptionsToString(sparams->utils, &opts, out);
1769 }
1770
1771 static int
1772 srp_server_mech_new(void *glob_context __attribute__((unused)),
1773                     sasl_server_params_t *params,
1774                     const char *challenge __attribute__((unused)),
1775                     unsigned challen __attribute__((unused)),
1776                     void **conn_context)
1777 {
1778     context_t *text;
1779     
1780     /* holds state are in */
1781     text = params->utils->malloc(sizeof(context_t));
1782     if (text == NULL) {
1783         MEMERROR(params->utils);
1784         return SASL_NOMEM;
1785     }
1786     
1787     memset(text, 0, sizeof(context_t));
1788     
1789     text->state = 1;
1790     text->utils = params->utils;
1791     text->md = EVP_get_digestbyname(server_mda->evp_name);
1792     
1793     *conn_context = text;
1794     
1795     return SASL_OK;
1796 }
1797
1798 static int srp_server_mech_step1(context_t *text,
1799                                  sasl_server_params_t *params,
1800                                  const char *clientin,
1801                                  unsigned clientinlen,
1802                                  const char **serverout,
1803                                  unsigned *serveroutlen,
1804                                  sasl_out_params_t *oparams)
1805 {
1806     int result;
1807     char *sid = NULL;
1808     char *cn = NULL;
1809     int cnlen;
1810     char *realm = NULL;
1811     char *user = NULL;
1812     const char *password_request[] = { "*cmusaslsecretSRP",
1813                                        SASL_AUX_PASSWORD,
1814                                        NULL };
1815     struct propval auxprop_values[3];
1816     
1817     /* Expect:
1818      *
1819      * U - authentication identity
1820      * I - authorization identity
1821      * sid - session id
1822      * cn - client nonce
1823      *
1824      * { utf8(U) utf8(I) utf8(sid) os(cn) }
1825      *
1826      */
1827     result = UnBuffer(params->utils, clientin, clientinlen,
1828                       "%s%s%s%o", &text->authid, &text->userid, &sid,
1829                       &cnlen, &cn);
1830     if (result) {
1831         params->utils->seterror(params->utils->conn, 0, 
1832                                 "Error UnBuffering input in step 1");
1833         return result;
1834     }
1835     /* Get the realm */
1836     result = _plug_parseuser(params->utils, &user, &realm, params->user_realm,
1837                              params->serverFQDN, text->authid);
1838     if (result) {
1839         params->utils->seterror(params->utils->conn, 0, 
1840                                 "Error getting realm");
1841         goto cleanup;
1842     }
1843     
1844     /* Generate N and g */
1845     result = generate_N_and_g(&text->N, &text->g);
1846     if (result) {
1847         params->utils->seterror(text->utils->conn, 0, 
1848                                 "Error calculating N and g");
1849         return result;
1850     }
1851     
1852     /* Get user secret */
1853     result = params->utils->prop_request(params->propctx, password_request);
1854     if (result != SASL_OK) goto cleanup;
1855     
1856     /* this will trigger the getting of the aux properties */
1857     result = params->canon_user(params->utils->conn,
1858                                 text->authid, 0, SASL_CU_AUTHID, oparams);
1859     if (result != SASL_OK) goto cleanup;
1860     
1861     result = params->canon_user(params->utils->conn,
1862                                 text->userid, 0, SASL_CU_AUTHZID, oparams);
1863     if (result != SASL_OK) goto cleanup;
1864     
1865     result = params->utils->prop_getnames(params->propctx, password_request,
1866                                           auxprop_values);
1867     if (result < 0 ||
1868         ((!auxprop_values[0].name || !auxprop_values[0].values) &&
1869          (!auxprop_values[1].name || !auxprop_values[1].values))) {
1870         /* We didn't find this username */
1871         params->utils->seterror(params->utils->conn,0,
1872                                 "no secret in database");
1873         result = params->transition ? SASL_TRANS : SASL_NOUSER;
1874         goto cleanup;
1875     }
1876     
1877     if (auxprop_values[0].name && auxprop_values[0].values) {
1878         char *mda = NULL;
1879         
1880         /* We have a precomputed verifier */
1881         result = ParseUserSecret(params->utils,
1882                                  (char*) auxprop_values[0].values[0],
1883                                  auxprop_values[0].valsize,
1884                                  &mda, &text->v, &text->salt, &text->saltlen);
1885         
1886         if (result) {
1887             /* ParseUserSecret sets error, if any */
1888             if (mda) params->utils->free(mda);
1889             goto cleanup;
1890         }
1891         
1892         /* find mda */
1893         server_mda = digest_options;
1894         while (server_mda->name) {
1895             if (!strcasecmp(server_mda->name, mda))
1896                 break;
1897             
1898             server_mda++;
1899         }
1900         
1901         if (!server_mda->name) {
1902             params->utils->seterror(params->utils->conn, 0,
1903                                     "unknown SRP mda '%s'", mda);
1904             params->utils->free(mda);
1905             result = SASL_FAIL;
1906             goto cleanup;
1907         }
1908         params->utils->free(mda);
1909         
1910     } else if (auxprop_values[1].name && auxprop_values[1].values) {
1911         /* We only have the password -- calculate the verifier */
1912         int len = strlen(auxprop_values[1].values[0]);
1913
1914         if (len == 0) {
1915             params->utils->seterror(params->utils->conn,0,
1916                                     "empty secret");
1917             result = SASL_FAIL;
1918             goto cleanup;
1919         }
1920         
1921         result = CalculateV(text, &text->N, &text->g, text->authid,
1922                             auxprop_values[1].values[0], len,
1923                             &text->v, &text->salt, &text->saltlen);
1924         if (result) {
1925             params->utils->seterror(params->utils->conn, 0, 
1926                                     "Error calculating v");
1927             goto cleanup;
1928         }
1929     } else {
1930         params->utils->seterror(params->utils->conn, 0,
1931                                 "Have neither type of secret");
1932         result = SASL_FAIL;
1933         goto cleanup;
1934     }    
1935     
1936     /* erase the plaintext password */
1937     params->utils->prop_erase(params->propctx, password_request[1]);
1938     
1939     /* Calculate B */
1940     result = CalculateB(text, &text->v, &text->N, &text->g,
1941                         &text->b, &text->B);
1942     if (result) {
1943         params->utils->seterror(params->utils->conn, 0, 
1944                                 "Error calculating B");
1945         return result;
1946     }
1947
1948     /* Create L */
1949     result = CreateServerOptions(params, &text->server_options);
1950     if (result) {
1951         params->utils->seterror(params->utils->conn, 0, 
1952                                 "Error creating server options");
1953         goto cleanup;
1954     }
1955     
1956     /* Send out:
1957      *
1958      * N - safe prime modulus
1959      * g - generator
1960      * s - salt
1961      * B - server's public key
1962      * L - server options (available layers etc)
1963      *
1964      * { 0x00 mpi(N) mpi(g) os(s) mpi(B) utf8(L) }
1965      *
1966      */
1967     result = MakeBuffer(text->utils, &text->out_buf, &text->out_buf_len,
1968                         serveroutlen, "%c%m%m%o%m%s",
1969                         0x00, &text->N, &text->g, text->saltlen, text->salt,
1970                         &text->B, text->server_options);
1971     if (result) {
1972         params->utils->seterror(params->utils->conn, 0, 
1973                                 "Error creating SRP buffer from data in step 1");
1974         goto cleanup;
1975     }
1976     *serverout = text->out_buf;
1977     
1978     text->state = 2;
1979     result = SASL_CONTINUE;
1980     
1981   cleanup:
1982     if (sid) params->utils->free(sid);
1983     if (cn) params->utils->free(cn);
1984     if (user) params->utils->free(user);
1985     if (realm) params->utils->free(realm);
1986     
1987     return result;
1988 }
1989
1990 static int srp_server_mech_step2(context_t *text,
1991                         sasl_server_params_t *params,
1992                         const char *clientin,
1993                         unsigned clientinlen,
1994                         const char **serverout,
1995                         unsigned *serveroutlen,
1996                         sasl_out_params_t *oparams)
1997 {
1998     int result;    
1999     char *M1 = NULL, *cIV = NULL; /* don't free */
2000     int M1len, cIVlen;
2001     srp_options_t client_opts;
2002     char myM1[EVP_MAX_MD_SIZE];
2003     int myM1len;
2004     int i;
2005     char M2[EVP_MAX_MD_SIZE];
2006     int M2len;
2007     char sIV[SRP_MAXBLOCKSIZE];
2008     
2009     /* Expect:
2010      *
2011      * A - client's public key
2012      * M1 - client evidence
2013      * o - client option list
2014      * cIV - client's initial vector
2015      *
2016      * { mpi(A) os(M1) utf8(o) os(cIV) }
2017      *
2018      */
2019     result = UnBuffer(params->utils, clientin, clientinlen,
2020                       "%m%-o%s%-o", &text->A, &M1len, &M1,
2021                       &text->client_options, &cIVlen, &cIV);
2022     if (result) {
2023         params->utils->seterror(params->utils->conn, 0, 
2024                                 "Error UnBuffering input in step 2");
2025         goto cleanup;
2026     }
2027     
2028     /* Per [SRP]: reject A <= 0 */
2029     if (BigIntCmpWord(&text->A, 0) <= 0) {
2030         SETERROR(params->utils, "Illegal value for 'A'\n");
2031         result = SASL_BADPROT;
2032         goto cleanup;
2033     }
2034
2035     /* parse client options */
2036     result = ParseOptions(params->utils, text->client_options, &client_opts, 1);
2037     if (result) {
2038         params->utils->seterror(params->utils->conn, 0, 
2039                                 "Error parsing user's options");
2040         
2041         if (client_opts.confidentiality) {
2042             /* Mark that we attempted confidentiality layer negotiation */
2043             oparams->mech_ssf = 2;
2044         }
2045         else if (client_opts.integrity || client_opts.replay_detection) {
2046             /* Mark that we attempted integrity layer negotiation */
2047             oparams->mech_ssf = 1;
2048         }
2049         return result;
2050     }
2051
2052     result = SetMDA(&client_opts, text);
2053     if (result) {
2054         params->utils->seterror(params->utils->conn, 0, 
2055                                 "Error setting options");
2056         return result;   
2057     }
2058
2059     /* Calculate K */
2060     result = ServerCalculateK(text, &text->v, &text->N, &text->A,
2061                               &text->b, &text->B, text->K, &text->Klen);
2062     if (result) {
2063         params->utils->seterror(params->utils->conn, 0, 
2064                                 "Error calculating K");
2065         return result;
2066     }
2067     
2068     /* See if M1 is correct */
2069     result = CalculateM1(text, &text->N, &text->g, text->authid,
2070                          text->salt, text->saltlen, &text->A, &text->B,
2071                          text->K, text->Klen, text->userid,
2072                          text->server_options, myM1, &myM1len);
2073     if (result) {
2074         params->utils->seterror(params->utils->conn, 0, 
2075                                 "Error calculating M1");
2076         goto cleanup;
2077     }
2078     
2079     if (myM1len != M1len) {
2080         params->utils->seterror(params->utils->conn, 0, 
2081                                 "SRP M1 lengths do not match");
2082         result = SASL_BADAUTH;
2083         goto cleanup;
2084     }
2085     
2086     for (i = 0; i < myM1len; i++) {
2087         if (myM1[i] != M1[i]) {
2088             params->utils->seterror(params->utils->conn, 0, 
2089                                     "client evidence does not match what we "
2090                                     "calculated. Probably a password error");
2091             result = SASL_BADAUTH;
2092             goto cleanup;
2093         }
2094     }
2095     
2096     /* calculate M2 to send */
2097     result = CalculateM2(text, &text->A, M1, M1len, text->K, text->Klen,
2098                          text->userid, text->client_options, "", 0,
2099                          M2, &M2len);
2100     if (result) {
2101         params->utils->seterror(params->utils->conn, 0, 
2102                                 "Error calculating M2 (server evidence)");
2103         goto cleanup;
2104     }
2105     
2106     /* Create sIV (server initial vector) */
2107     text->utils->rand(text->utils->rpool, sIV, sizeof(sIV));
2108     
2109     /*
2110      * Send out:
2111      * M2 - server evidence
2112      * sIV - server's initial vector
2113      * sid - session id
2114      * ttl - time to live
2115      *
2116      * { os(M2) os(sIV) utf8(sid) uint(ttl) }
2117      */
2118     result = MakeBuffer(text->utils, &text->out_buf, &text->out_buf_len,
2119                         serveroutlen, "%o%o%s%u", M2len, M2,
2120                         sizeof(sIV), sIV, "", 0);
2121     if (result) {
2122         params->utils->seterror(params->utils->conn, 0, 
2123                                 "Error making output buffer in SRP step 3");
2124         goto cleanup;
2125     }
2126     *serverout = text->out_buf;
2127
2128     /* configure security layer */
2129     result = LayerInit(&client_opts, text, oparams, cIV, sIV,
2130                        params->props.maxbufsize);
2131     if (result) {
2132         params->utils->seterror(params->utils->conn, 0, 
2133                                 "Error initializing security layer");
2134         return result;   
2135     }
2136
2137     /* set oparams */
2138     oparams->doneflag = 1;
2139     oparams->param_version = 0;
2140     
2141     result = SASL_OK;
2142     
2143   cleanup:
2144     
2145     return result;
2146 }
2147
2148 static int srp_server_mech_step(void *conn_context,
2149                                 sasl_server_params_t *sparams,
2150                                 const char *clientin,
2151                                 unsigned clientinlen,
2152                                 const char **serverout,
2153                                 unsigned *serveroutlen,
2154                                 sasl_out_params_t *oparams)
2155 {
2156     context_t *text = (context_t *) conn_context;
2157     
2158     if (!sparams
2159         || !serverout
2160         || !serveroutlen
2161         || !oparams)
2162         return SASL_BADPARAM;
2163     
2164     sparams->utils->log(NULL, SASL_LOG_DEBUG,
2165                         "SRP server step %d\n", text->state);
2166     
2167     *serverout = NULL;
2168     *serveroutlen = 0;
2169         
2170     switch (text->state) {
2171
2172     case 1:
2173         return srp_server_mech_step1(text, sparams, clientin, clientinlen,
2174                                      serverout, serveroutlen, oparams);
2175
2176     case 2:
2177         return srp_server_mech_step2(text, sparams, clientin, clientinlen,
2178                                      serverout, serveroutlen, oparams);
2179
2180     default:
2181         sparams->utils->seterror(sparams->utils->conn, 0,
2182                                  "Invalid SRP server step %d", text->state);
2183         return SASL_FAIL;
2184     }
2185     
2186     return SASL_FAIL; /* should never get here */
2187 }
2188
2189 #ifdef DO_SRP_SETPASS
2190 static int srp_setpass(void *glob_context __attribute__((unused)),
2191                        sasl_server_params_t *sparams,
2192                        const char *userstr,
2193                        const char *pass,
2194                        unsigned passlen __attribute__((unused)),
2195                        const char *oldpass __attribute__((unused)),
2196                        unsigned oldpasslen __attribute__((unused)),
2197                        unsigned flags)
2198 {
2199     int r;
2200     char *user = NULL;
2201     char *user_only = NULL;
2202     char *realm = NULL;
2203     sasl_secret_t *sec = NULL;
2204     struct propctx *propctx = NULL;
2205     const char *store_request[] = { "cmusaslsecretSRP",
2206                                      NULL };
2207     
2208     /* Do we have a backend that can store properties? */
2209     if (!sparams->utils->auxprop_store ||
2210         sparams->utils->auxprop_store(NULL, NULL, NULL) != SASL_OK) {
2211         SETERROR(sparams->utils, "SRP: auxprop backend can't store properties");
2212         return SASL_NOMECH;
2213     }
2214     
2215     /* NB: Ideally we need to canonicalize userstr here */
2216     r = _plug_parseuser(sparams->utils, &user_only, &realm, sparams->user_realm,
2217                         sparams->serverFQDN, userstr);
2218
2219     if (r) {
2220         sparams->utils->seterror(sparams->utils->conn, 0, 
2221                                  "Error parsing user");
2222         return r;
2223     }
2224
2225     r = _plug_make_fulluser(sparams->utils, &user, user_only, realm);
2226
2227     if (r) {
2228         goto end;
2229     }
2230
2231     if ((flags & SASL_SET_DISABLE) || pass == NULL) {
2232         sec = NULL;
2233     } else {
2234         context_t *text;
2235         BIGNUM N;
2236         BIGNUM g;
2237         BIGNUM v;
2238         char *salt;
2239         int saltlen;
2240         char *buffer = NULL;
2241         int bufferlen, alloclen, encodelen;
2242         
2243         text = sparams->utils->malloc(sizeof(context_t));
2244         if (text == NULL) {
2245             MEMERROR(sparams->utils);
2246             return SASL_NOMEM;
2247         }
2248         
2249         memset(text, 0, sizeof(context_t));
2250         
2251         text->utils = sparams->utils;
2252         text->md = EVP_get_digestbyname(server_mda->evp_name);
2253         
2254         r = generate_N_and_g(&N, &g);
2255         if (r) {
2256             sparams->utils->seterror(sparams->utils->conn, 0, 
2257                                      "Error calculating N and g");
2258             goto end;
2259         }
2260
2261         /* user is a full username here */
2262         r = CalculateV(text, &N, &g, user, pass, passlen, &v, &salt, &saltlen);
2263         if (r) {
2264             sparams->utils->seterror(sparams->utils->conn, 0, 
2265                                      "Error calculating v");
2266             goto end;
2267         }
2268         
2269         /* The secret data is stored as suggested in RFC 2945:
2270          *
2271          *  { utf8(mda) mpi(v) os(salt) }  (base64 encoded)
2272          */
2273         
2274         r = MakeBuffer(text->utils, &text->out_buf, &text->out_buf_len,
2275                        &bufferlen, "%s%m%o",
2276                        server_mda->name, &v, saltlen, salt);
2277         
2278         if (r) {
2279             sparams->utils->seterror(sparams->utils->conn, 0, 
2280                                      "Error making buffer for secret");
2281             goto end;
2282         }
2283         buffer = text->out_buf;
2284         
2285         /* Put 'buffer' into sasl_secret_t.
2286          * This will be base64 encoded, so make sure its big enough.
2287          */
2288         alloclen = (bufferlen/3 + 1) * 4 + 1;
2289         sec = sparams->utils->malloc(sizeof(sasl_secret_t)+alloclen);
2290         if (!sec) {
2291             r = SASL_NOMEM;
2292             goto end;
2293         }
2294         sparams->utils->encode64(buffer, bufferlen, sec->data, alloclen,
2295                                  &encodelen);
2296         sec->len = encodelen;
2297         
2298         /* Clean everything up */
2299       end:
2300         if (buffer) sparams->utils->free((void *) buffer);
2301         BN_clear_free(&N);
2302         BN_clear_free(&g);
2303         BN_clear_free(&v);
2304         sparams->utils->free(text);
2305         
2306         if (r) return r;
2307     }
2308     
2309     /* do the store */
2310     propctx = sparams->utils->prop_new(0);
2311     if (!propctx)
2312         r = SASL_FAIL;
2313     if (!r)
2314         r = sparams->utils->prop_request(propctx, store_request);
2315     if (!r)
2316         r = sparams->utils->prop_set(propctx, "cmusaslsecretSRP",
2317                                      (sec ? sec->data : NULL),
2318                                      (sec ? sec->len : 0));
2319     if (!r)
2320         r = sparams->utils->auxprop_store(sparams->utils->conn, propctx, user);
2321     if (propctx)
2322         sparams->utils->prop_dispose(&propctx);
2323     
2324     if (r) {
2325         sparams->utils->seterror(sparams->utils->conn, 0, 
2326                                  "Error putting SRP secret");
2327         goto cleanup;
2328     }
2329     
2330     sparams->utils->log(NULL, SASL_LOG_DEBUG, "Setpass for SRP successful\n");
2331     
2332   cleanup:
2333     
2334     if (user)   _plug_free_string(sparams->utils, &user);
2335     if (user_only)      _plug_free_string(sparams->utils, &user_only);
2336     if (realm)  _plug_free_string(sparams->utils, &realm);
2337     if (sec)    _plug_free_secret(sparams->utils, &sec);
2338     
2339     return r;
2340 }
2341 #endif /* DO_SRP_SETPASS */
2342
2343 static int srp_mech_avail(void *glob_context __attribute__((unused)),
2344                           sasl_server_params_t *sparams,
2345                           void **conn_context __attribute__((unused))) 
2346 {
2347     /* Do we have access to the selected MDA? */
2348     if (!server_mda || !server_mda->enabled) {
2349         SETERROR(sparams->utils,
2350                  "SRP unavailable due to selected MDA unavailable");
2351         return SASL_NOMECH;
2352     }
2353     
2354     return SASL_OK;
2355 }
2356
2357 static sasl_server_plug_t srp_server_plugins[] = 
2358 {
2359     {
2360         "SRP",                          /* mech_name */
2361         0,                              /* max_ssf */
2362         SASL_SEC_NOPLAINTEXT
2363         | SASL_SEC_NOANONYMOUS
2364         | SASL_SEC_NOACTIVE
2365         | SASL_SEC_NODICTIONARY
2366         | SASL_SEC_FORWARD_SECRECY
2367         | SASL_SEC_MUTUAL_AUTH,         /* security_flags */
2368         SASL_FEAT_WANT_CLIENT_FIRST
2369         | SASL_FEAT_ALLOWS_PROXY,       /* features */
2370         NULL,                           /* glob_context */
2371         &srp_server_mech_new,           /* mech_new */
2372         &srp_server_mech_step,          /* mech_step */
2373         &srp_common_mech_dispose,       /* mech_dispose */
2374         &srp_common_mech_free,          /* mech_free */
2375 #ifdef DO_SRP_SETPASS
2376         &srp_setpass,                   /* setpass */
2377 #else
2378         NULL,
2379 #endif
2380         NULL,                           /* user_query */
2381         NULL,                           /* idle */
2382         &srp_mech_avail,                /* mech avail */
2383         NULL                            /* spare */
2384     }
2385 };
2386
2387 int srp_server_plug_init(const sasl_utils_t *utils,
2388                          int maxversion,
2389                          int *out_version,
2390                          const sasl_server_plug_t **pluglist,
2391                          int *plugcount,
2392                          const char *plugname __attribute__((unused)))
2393 {
2394     const char *mda;
2395     unsigned int len;
2396     layer_option_t *opts;
2397     
2398     if (maxversion < SASL_SERVER_PLUG_VERSION) {
2399         SETERROR(utils, "SRP version mismatch");
2400         return SASL_BADVERS;
2401     }
2402     
2403     utils->getopt(utils->getopt_context, "SRP", "srp_mda", &mda, &len);
2404     if (!mda) mda = DEFAULT_MDA;
2405     
2406     /* Add all digests and ciphers */
2407     OpenSSL_add_all_algorithms();
2408     
2409     /* See which digests we have available and set max_ssf accordingly */
2410     opts = digest_options;
2411     while (opts->name) {
2412         if (EVP_get_digestbyname(opts->evp_name)) {
2413             opts->enabled = 1;
2414             
2415             srp_server_plugins[0].max_ssf = opts->ssf;
2416         }
2417         
2418         /* Locate the server MDA */
2419         if (!strcasecmp(opts->name, mda) || !strcasecmp(opts->evp_name, mda)) {
2420             server_mda = opts;
2421         }
2422         
2423         opts++;
2424     }
2425     
2426     /* See which ciphers we have available and set max_ssf accordingly */
2427     opts = cipher_options;
2428     while (opts->name) {
2429         if (EVP_get_cipherbyname(opts->evp_name)) {
2430             opts->enabled = 1;
2431             
2432             if (opts->ssf > srp_server_plugins[0].max_ssf) {
2433                 srp_server_plugins[0].max_ssf = opts->ssf;
2434             }
2435         }
2436         
2437         opts++;
2438     }
2439     
2440     *out_version = SASL_SERVER_PLUG_VERSION;
2441     *pluglist = srp_server_plugins;
2442     *plugcount = 1;
2443     
2444     return SASL_OK;
2445 }
2446
2447 /*****************************  Client Section  *****************************/
2448
2449 /* Check to see if N,g is in the recommended list */
2450 static int check_N_and_g(const sasl_utils_t *utils, BIGNUM *N, BIGNUM *g)
2451 {
2452     char *N_prime;
2453     unsigned long g_prime;
2454     unsigned i;
2455     int r = SASL_FAIL;
2456     
2457     N_prime = BN_bn2hex(N);
2458     g_prime = BN_get_word(g);
2459     
2460     for (i = 0; i < NUM_Ng; i++) {
2461         if (!strcasecmp(N_prime, Ng_tab[i].N) && (g_prime == Ng_tab[i].g)) {
2462             r = SASL_OK;
2463             break;
2464         }
2465     }
2466     
2467     if (N_prime) utils->free(N_prime);
2468     
2469     return r;
2470 }
2471
2472 static int CalculateA(context_t *text  __attribute__((unused)),
2473                       BIGNUM *N, BIGNUM *g, BIGNUM *a, BIGNUM *A)
2474 {
2475     BN_CTX *ctx = BN_CTX_new();
2476     
2477     /* Generate a */
2478     GetRandBigInt(a);
2479         
2480     /* Per [SRP]: make sure a > log[g](N) -- g is always 2 */
2481     BN_add_word(a, BN_num_bits(N));
2482         
2483     /* A = g^a % N */
2484     BN_init(A);
2485     BN_mod_exp(A, g, a, N, ctx);
2486
2487     BN_CTX_free(ctx);
2488     
2489     return SASL_OK;
2490 }
2491         
2492 static int ClientCalculateK(context_t *text, char *salt, int saltlen,
2493                             char *user, char *pass, int passlen,
2494                             BIGNUM *N, BIGNUM *g, BIGNUM *a, BIGNUM *A,
2495                             BIGNUM *B, char *K, int *Klen)
2496 {
2497     int r;
2498     unsigned char hash[EVP_MAX_MD_SIZE];
2499     int hashlen;
2500     BIGNUM x;
2501     BIGNUM u;
2502     BIGNUM aux;
2503     BIGNUM gx;
2504     BIGNUM gx3;
2505     BIGNUM base;
2506     BIGNUM S;
2507     BN_CTX *ctx = BN_CTX_new();
2508     
2509     /* u = H(A | B) */
2510     r = MakeHash(text->md, hash, &hashlen, "%m%m", A, B);
2511     if (r) goto err;
2512     BN_init(&u);
2513     BN_bin2bn(hash, hashlen, &u);
2514     
2515     /* per Tom Wu: make sure u != 0 */
2516     if (BN_is_zero(&u)) {
2517         SETERROR(text->utils, "SRP: Illegal value for 'u'\n");
2518         r = SASL_BADPROT;
2519         goto err;
2520     }
2521     
2522     /* S = (B - 3(g^x)) ^ (a + ux) % N */
2523
2524     r = CalculateX(text, salt, saltlen, user, pass, passlen, &x);
2525     if (r) return r;
2526     
2527     /* a + ux */
2528     BN_init(&aux);
2529     BN_mul(&aux, &u, &x, ctx);
2530     BN_add(&aux, &aux, a);
2531     
2532     /* gx3 = 3(g^x) % N */
2533     BN_init(&gx);
2534     BN_mod_exp(&gx, g, &x, N, ctx);
2535     BN_init(&gx3);
2536     BN_set_word(&gx3, 3);
2537     BN_mod_mul(&gx3, &gx3, &gx, N, ctx);
2538     
2539     /* base = (B - 3(g^x)) % N */
2540     BN_init(&base);
2541 #if OPENSSL_VERSION_NUMBER >= 0x00907000L
2542     BN_mod_sub(&base, B, &gx3, N, ctx);
2543 #else
2544     BN_sub(&base, B, &gx3);
2545     BN_mod(&base, &base, N, ctx);
2546     if (BigIntCmpWord(&base, 0) < 0) {
2547         BN_add(&base, &base, N);
2548     }
2549 #endif
2550     
2551     /* S = base^aux % N */
2552     BN_init(&S);
2553     BN_mod_exp(&S, &base, &aux, N, ctx);
2554     
2555     /* K = H(S) */
2556     r = MakeHash(text->md, K, Klen, "%m", &S);
2557     if (r) goto err;
2558     
2559     r = SASL_OK;
2560     
2561   err:
2562     BN_CTX_free(ctx);
2563     BN_clear_free(&x);
2564     BN_clear_free(&u);
2565     BN_clear_free(&aux);
2566     BN_clear_free(&gx);
2567     BN_clear_free(&gx3);
2568     BN_clear_free(&base);
2569     BN_clear_free(&S);
2570     
2571     return r;
2572 }
2573
2574 static int CreateClientOpts(sasl_client_params_t *params, 
2575                             srp_options_t *available, 
2576                             srp_options_t *out)
2577 {
2578     layer_option_t *opt;
2579     sasl_ssf_t external;
2580     sasl_ssf_t limit;
2581     sasl_ssf_t musthave;
2582     
2583     /* zero out output */
2584     memset(out, 0, sizeof(srp_options_t));
2585     
2586     params->utils->log(NULL, SASL_LOG_DEBUG,
2587                        "Available MDA = %d\n", available->mda);
2588     
2589     /* mda */
2590     opt = FindBest(available->mda, 0, 256, digest_options);
2591     
2592     if (opt) {
2593         out->mda = opt->bit;
2594     }
2595     else {
2596         SETERROR(params->utils, "Can't find an acceptable SRP MDA\n");
2597         return SASL_BADAUTH;
2598     }
2599     
2600     /* get requested ssf */
2601     external = params->external_ssf;
2602     
2603     /* what do we _need_?  how much is too much? */
2604     if(params->props.maxbufsize == 0) {
2605         musthave = 0;
2606         limit = 0;
2607     } else {
2608         if (params->props.max_ssf > external) {
2609             limit = params->props.max_ssf - external;
2610         } else {
2611             limit = 0;
2612         }
2613         if (params->props.min_ssf > external) {
2614             musthave = params->props.min_ssf - external;
2615         } else {
2616             musthave = 0;
2617         }
2618     }
2619         
2620     /* we now go searching for an option that gives us at least "musthave"
2621        and at most "limit" bits of ssf. */
2622     params->utils->log(NULL, SASL_LOG_DEBUG,
2623                        "Available confidentiality = %d  "
2624                        "musthave = %d  limit = %d",
2625                        available->confidentiality, musthave, limit);
2626     
2627     /* confidentiality */
2628     if (limit > 1) {
2629         
2630         opt = FindBest(available->confidentiality, musthave, limit,
2631                        cipher_options);
2632         
2633         if (opt) {
2634             out->confidentiality = opt->bit;
2635             /* we've already satisfied the SSF with the confidentiality
2636              * layer, but we'll also use an integrity layer if we can
2637              */
2638             musthave = 0;
2639         }
2640         else if (musthave > 1) {
2641             SETERROR(params->utils,
2642                      "Can't find an acceptable SRP confidentiality layer\n");
2643             return SASL_TOOWEAK;
2644         }
2645     }
2646     
2647     params->utils->log(NULL, SASL_LOG_DEBUG,
2648                        "Available integrity = %d "
2649                        "musthave = %d  limit = %d",
2650                        available->integrity, musthave, limit);
2651     
2652     /* integrity */
2653     if ((limit >= 1) && (musthave <= 1)) {
2654         
2655         opt = FindBest(available->integrity, musthave, limit,
2656                        digest_options);
2657         
2658         if (opt) {
2659             out->integrity = opt->bit;
2660             
2661             /* if we set an integrity option we can set replay detection */
2662             out->replay_detection = available->replay_detection;
2663         }
2664         else if (musthave > 0) {
2665             SETERROR(params->utils,
2666                      "Can't find an acceptable SRP integrity layer\n");
2667             return SASL_TOOWEAK;
2668         }
2669     }
2670     
2671     /* Check to see if we've satisfied all of the servers mandatory layers */
2672     params->utils->log(NULL, SASL_LOG_DEBUG,
2673                        "Mandatory layers = %d\n",available->mandatory);
2674     
2675     if ((!out->replay_detection &&
2676          (available->mandatory & BIT_REPLAY_DETECTION)) ||
2677         (!out->integrity &&
2678          (available->mandatory & BIT_INTEGRITY)) ||
2679         (!out->confidentiality &&
2680          (available->mandatory & BIT_CONFIDENTIALITY))) {
2681         SETERROR(params->utils, "Mandatory SRP layer not supported\n");
2682         return SASL_BADAUTH;
2683     }
2684     
2685     /* Add maxbuffersize */
2686     out->maxbufsize = SRP_MAXBUFFERSIZE;
2687     if (params->props.maxbufsize && params->props.maxbufsize < out->maxbufsize)
2688         out->maxbufsize = params->props.maxbufsize;
2689     
2690     return SASL_OK;
2691 }
2692
2693 static int srp_client_mech_new(void *glob_context __attribute__((unused)),
2694                                sasl_client_params_t *params,
2695                                void **conn_context)
2696 {
2697     context_t *text;
2698     
2699     /* holds state are in */
2700     text = params->utils->malloc(sizeof(context_t));
2701     if (text == NULL) {
2702         MEMERROR( params->utils );
2703         return SASL_NOMEM;
2704     }
2705     
2706     memset(text, 0, sizeof(context_t));
2707     
2708     text->state = 1;
2709     text->utils = params->utils;
2710
2711     *conn_context = text;
2712     
2713     return SASL_OK;
2714 }
2715
2716 static int
2717 srp_client_mech_step1(context_t *text,
2718                       sasl_client_params_t *params,
2719                       const char *serverin __attribute__((unused)),
2720                       unsigned serverinlen,
2721                       sasl_interact_t **prompt_need,
2722                       const char **clientout,
2723                       unsigned *clientoutlen,
2724                       sasl_out_params_t *oparams)
2725 {
2726     const char *authid = NULL, *userid = NULL;
2727     int auth_result = SASL_OK;
2728     int pass_result = SASL_OK;
2729     int user_result = SASL_OK;
2730     int result;
2731     
2732     /* Expect: 
2733      *   absolutely nothing
2734      * 
2735      */
2736     if (serverinlen > 0) {
2737         SETERROR(params->utils, "Invalid input to first step of SRP\n");
2738         return SASL_BADPROT;
2739     }
2740     
2741     /* try to get the authid */
2742     if (oparams->authid==NULL) {
2743         auth_result = _plug_get_authid(params->utils, &authid, prompt_need);
2744         
2745         if ((auth_result != SASL_OK) && (auth_result != SASL_INTERACT))
2746             return auth_result;
2747     }
2748     
2749     /* try to get the userid */
2750     if (oparams->user == NULL) {
2751         user_result = _plug_get_userid(params->utils, &userid, prompt_need);
2752         
2753         if ((user_result != SASL_OK) && (user_result != SASL_INTERACT))
2754             return user_result;
2755     }
2756     
2757     /* try to get the password */
2758     if (text->password == NULL) {
2759         pass_result=_plug_get_password(params->utils, &text->password,
2760                                        &text->free_password, prompt_need);
2761             
2762         if ((pass_result != SASL_OK) && (pass_result != SASL_INTERACT))
2763             return pass_result;
2764     }
2765     
2766     /* free prompts we got */
2767     if (prompt_need && *prompt_need) {
2768         params->utils->free(*prompt_need);
2769         *prompt_need = NULL;
2770     }
2771     
2772     /* if there are prompts not filled in */
2773     if ((auth_result == SASL_INTERACT) || (user_result == SASL_INTERACT) ||
2774         (pass_result == SASL_INTERACT)) {
2775         /* make the prompt list */
2776         result =
2777             _plug_make_prompts(params->utils, prompt_need,
2778                                user_result == SASL_INTERACT ?
2779                                "Please enter your authorization name" : NULL,
2780                                NULL,
2781                                auth_result == SASL_INTERACT ?
2782                                "Please enter your authentication name" : NULL,
2783                                NULL,
2784                                pass_result == SASL_INTERACT ?
2785                                "Please enter your password" : NULL, NULL,
2786                                NULL, NULL, NULL,
2787                                NULL, NULL, NULL);
2788         if (result != SASL_OK) return result;
2789             
2790         return SASL_INTERACT;
2791     }
2792     
2793     if (!userid || !*userid) {
2794         result = params->canon_user(params->utils->conn, authid, 0,
2795                                     SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams);
2796     }
2797     else {
2798         result = params->canon_user(params->utils->conn, authid, 0,
2799                                     SASL_CU_AUTHID, oparams);
2800         if (result != SASL_OK) return result;
2801
2802         result = params->canon_user(params->utils->conn, userid, 0,
2803                                     SASL_CU_AUTHZID, oparams);
2804     }
2805     if (result != SASL_OK) return result;
2806     
2807     /* Send out:
2808      *
2809      * U - authentication identity 
2810      * I - authorization identity
2811      * sid - previous session id
2812      * cn - client nonce
2813      *
2814      * { utf8(U) utf8(I) utf8(sid) os(cn) }
2815      */
2816     result = MakeBuffer(text->utils, &text->out_buf, &text->out_buf_len,
2817                         clientoutlen, "%s%s%s%o",
2818                         (char *) oparams->authid, (char *) oparams->user,
2819                         "", 0, "");
2820     if (result) {
2821         params->utils->log(NULL, SASL_LOG_ERR, "Error making output buffer\n");
2822         goto cleanup;
2823     }
2824     *clientout = text->out_buf;
2825     
2826     text->state = 2;
2827
2828     result = SASL_CONTINUE;
2829     
2830   cleanup:
2831     
2832     return result;
2833 }
2834
2835 static int
2836 srp_client_mech_step2(context_t *text,
2837                       sasl_client_params_t *params,
2838                       const char *serverin,
2839                       unsigned serverinlen,
2840                       sasl_interact_t **prompt_need __attribute__((unused)),
2841                       const char **clientout,
2842                       unsigned *clientoutlen,
2843                       sasl_out_params_t *oparams)
2844 {
2845     int result;
2846     char reuse;
2847     srp_options_t server_opts;
2848     
2849     /* Expect:
2850      *
2851      *  { 0x00 mpi(N) mpi(g) os(s) mpi(B) utf8(L) }
2852      */
2853     result = UnBuffer(params->utils, serverin, serverinlen,
2854                       "%c%m%m%o%m%s", &reuse, &text->N, &text->g,
2855                       &text->saltlen, &text->salt, &text->B,
2856                       &text->server_options);
2857     if (result) {
2858         params->utils->seterror(params->utils->conn, 0, 
2859                                 "Error UnBuffering input in step 2");
2860         goto cleanup;
2861     }
2862
2863     /* Check N and g to see if they are one of the recommended pairs */
2864     result = check_N_and_g(params->utils, &text->N, &text->g);
2865     if (result) {
2866         params->utils->log(NULL, SASL_LOG_ERR,
2867                            "Values of 'N' and 'g' are not recommended\n");
2868         goto cleanup;
2869     }
2870     
2871     /* Per [SRP]: reject B <= 0, B >= N */
2872     if (BigIntCmpWord(&text->B, 0) <= 0 || BN_cmp(&text->B, &text->N) >= 0) {
2873         SETERROR(params->utils, "Illegal value for 'B'\n");
2874         result = SASL_BADPROT;
2875         goto cleanup;
2876     }
2877
2878     /* parse server options */
2879     memset(&server_opts, 0, sizeof(srp_options_t));
2880     result = ParseOptions(params->utils, text->server_options, &server_opts, 0);
2881     if (result) {
2882         params->utils->log(NULL, SASL_LOG_ERR,
2883                            "Error parsing SRP server options\n");
2884         goto cleanup;
2885     }
2886     
2887     /* Create o */
2888     result = CreateClientOpts(params, &server_opts, &text->client_opts);
2889     if (result) {
2890         params->utils->log(NULL, SASL_LOG_ERR,
2891                            "Error creating client options\n");
2892         goto cleanup;
2893     }
2894     
2895     result = OptionsToString(params->utils, &text->client_opts,
2896                              &text->client_options);
2897     if (result) {
2898         params->utils->log(NULL, SASL_LOG_ERR,
2899                            "Error converting client options to an option string\n");
2900         goto cleanup;
2901     }
2902
2903     result = SetMDA(&text->client_opts, text);
2904     if (result) {
2905         params->utils->seterror(params->utils->conn, 0, 
2906                                 "Error setting MDA");
2907         goto cleanup;
2908     }
2909
2910     /* Calculate A */
2911     result = CalculateA(text, &text->N, &text->g, &text->a, &text->A);
2912     if (result) {
2913         params->utils->seterror(params->utils->conn, 0, 
2914                                 "Error calculating A");
2915         return result;
2916     }
2917     
2918     /* Calculate shared context key K */
2919     result = ClientCalculateK(text, text->salt, text->saltlen,
2920                               (char *) oparams->authid, 
2921                               text->password->data, text->password->len,
2922                               &text->N, &text->g, &text->a, &text->A, &text->B,
2923                               text->K, &text->Klen);
2924     if (result) {
2925         params->utils->log(NULL, SASL_LOG_ERR,
2926                            "Error creating K\n");
2927         goto cleanup;
2928     }
2929     
2930     /* Calculate M1 (client evidence) */
2931     result = CalculateM1(text, &text->N, &text->g, (char *) oparams->authid,
2932                          text->salt, text->saltlen, &text->A, &text->B,
2933                          text->K, text->Klen, (char *) oparams->user,
2934                          text->server_options, text->M1, &text->M1len);
2935     if (result) {
2936         params->utils->log(NULL, SASL_LOG_ERR,
2937                            "Error creating M1\n");
2938         goto cleanup;
2939     }
2940
2941     /* Create cIV (client initial vector) */
2942     text->utils->rand(text->utils->rpool, text->cIV, sizeof(text->cIV));
2943     
2944     /* Send out:
2945      *
2946      * A - client's public key
2947      * M1 - client evidence
2948      * o - client option list
2949      * cIV - client initial vector
2950      *
2951      * { mpi(A) os(M1) utf8(o) os(cIV) }
2952      */
2953     result = MakeBuffer(text->utils, &text->out_buf, &text->out_buf_len,
2954                         clientoutlen, "%m%o%s%o",
2955                         &text->A, text->M1len, text->M1, text->client_options,
2956                         sizeof(text->cIV), text->cIV);
2957     if (result) {
2958         params->utils->log(NULL, SASL_LOG_ERR, "Error making output buffer\n");
2959         goto cleanup;
2960     }
2961     *clientout = text->out_buf;
2962     
2963     text->state = 3;
2964
2965     result = SASL_CONTINUE;
2966     
2967   cleanup:
2968     
2969     return result;
2970 }
2971
2972 static int
2973 srp_client_mech_step3(context_t *text,
2974                       sasl_client_params_t *params,
2975                       const char *serverin,
2976                       unsigned serverinlen,
2977                       sasl_interact_t **prompt_need __attribute__((unused)),
2978                       const char **clientout __attribute__((unused)),
2979                       unsigned *clientoutlen __attribute__((unused)),
2980                       sasl_out_params_t *oparams)
2981 {
2982     int result;    
2983     char *M2 = NULL, *sIV = NULL; /* don't free */
2984     char *sid = NULL;
2985     int M2len, sIVlen;
2986     uint32 ttl;
2987     int i;
2988     char myM2[EVP_MAX_MD_SIZE];
2989     int myM2len;
2990     
2991     /* Expect:
2992      *
2993      * M2 - server evidence
2994      * sIV - server initial vector
2995      * sid - session id
2996      * ttl - time to live
2997      *
2998      *   { os(M2) os(sIV) utf8(sid) uint(ttl) }
2999      */
3000     result = UnBuffer(params->utils, serverin, serverinlen,
3001                       "%-o%-o%s%u", &M2len, &M2, &sIVlen, &sIV,
3002                       &sid, &ttl);
3003     if (result) {
3004         params->utils->seterror(params->utils->conn, 0, 
3005                                 "Error UnBuffering input in step 3");
3006         goto cleanup;
3007     }
3008
3009     /* calculate our own M2 */
3010     result = CalculateM2(text, &text->A, text->M1, text->M1len,
3011                          text->K, text->Klen, (char *) oparams->user,
3012                          text->client_options, "", 0,
3013                          myM2, &myM2len);
3014     if (result) {
3015         params->utils->log(NULL, SASL_LOG_ERR,
3016                            "Error calculating our own M2 (server evidence)\n");
3017         goto cleanup;
3018     }
3019     
3020     /* compare to see if is server spoof */
3021     if (myM2len != M2len) {
3022         SETERROR(params->utils, "SRP Server M2 length wrong\n");
3023         result = SASL_BADSERV;
3024         goto cleanup;
3025     }
3026     
3027     
3028     for (i = 0; i < myM2len; i++) {
3029         if (M2[i] != myM2[i]) {
3030             SETERROR(params->utils,
3031                      "SRP Server spoof detected. M2 incorrect\n");
3032             result = SASL_BADSERV;
3033             goto cleanup;
3034         }
3035     }
3036     
3037     /*
3038      * Send out: nothing
3039      */
3040
3041     /* configure security layer */
3042     result = LayerInit(&text->client_opts, text, oparams, sIV, text->cIV,
3043                        params->props.maxbufsize);
3044     if (result) {
3045         params->utils->seterror(params->utils->conn, 0, 
3046                                 "Error initializing security layer");
3047         return result;   
3048     }
3049
3050     /* set oparams */
3051     oparams->doneflag = 1;
3052     oparams->param_version = 0;
3053
3054     result = SASL_OK;
3055     
3056   cleanup:
3057     if (sid) params->utils->free(sid);
3058     
3059     return result;
3060 }
3061
3062 static int srp_client_mech_step(void *conn_context,
3063                                 sasl_client_params_t *params,
3064                                 const char *serverin,
3065                                 unsigned serverinlen,
3066                                 sasl_interact_t **prompt_need,
3067                                 const char **clientout,
3068                                 unsigned *clientoutlen,
3069                                 sasl_out_params_t *oparams)
3070 {
3071     context_t *text = (context_t *) conn_context;
3072     
3073     params->utils->log(NULL, SASL_LOG_DEBUG,
3074                        "SRP client step %d\n", text->state);
3075     
3076     *clientout = NULL;
3077     *clientoutlen = 0;
3078     
3079     switch (text->state) {
3080
3081     case 1:
3082         return srp_client_mech_step1(text, params, serverin, serverinlen, 
3083                                      prompt_need, clientout, clientoutlen,
3084                                      oparams);
3085
3086     case 2:
3087         return srp_client_mech_step2(text, params, serverin, serverinlen, 
3088                                      prompt_need, clientout, clientoutlen,
3089                                      oparams);
3090
3091     case 3:
3092         return srp_client_mech_step3(text, params, serverin, serverinlen, 
3093                                      prompt_need, clientout, clientoutlen,
3094                                      oparams);
3095
3096     default:
3097         params->utils->log(NULL, SASL_LOG_ERR,
3098                            "Invalid SRP client step %d\n", text->state);
3099         return SASL_FAIL;
3100     }
3101     
3102     return SASL_FAIL; /* should never get here */
3103 }
3104
3105
3106 static sasl_client_plug_t srp_client_plugins[] = 
3107 {
3108     {
3109         "SRP",                          /* mech_name */
3110         0,                              /* max_ssf */
3111         SASL_SEC_NOPLAINTEXT
3112         | SASL_SEC_NOANONYMOUS
3113         | SASL_SEC_NOACTIVE
3114         | SASL_SEC_NODICTIONARY
3115         | SASL_SEC_FORWARD_SECRECY
3116         | SASL_SEC_MUTUAL_AUTH,         /* security_flags */
3117         SASL_FEAT_WANT_CLIENT_FIRST
3118         | SASL_FEAT_ALLOWS_PROXY,       /* features */
3119         NULL,                           /* required_prompts */
3120         NULL,                           /* glob_context */
3121         &srp_client_mech_new,           /* mech_new */
3122         &srp_client_mech_step,          /* mech_step */
3123         &srp_common_mech_dispose,       /* mech_dispose */
3124         &srp_common_mech_free,          /* mech_free */
3125         NULL,                           /* idle */
3126         NULL,                           /* spare */
3127         NULL                            /* spare */
3128     }
3129 };
3130
3131 int srp_client_plug_init(const sasl_utils_t *utils __attribute__((unused)),
3132                          int maxversion,
3133                          int *out_version,
3134                          const sasl_client_plug_t **pluglist,
3135                          int *plugcount,
3136                          const char *plugname __attribute__((unused)))
3137 {
3138     layer_option_t *opts;
3139     
3140     if (maxversion < SASL_CLIENT_PLUG_VERSION) {
3141         SETERROR(utils, "SRP version mismatch");
3142         return SASL_BADVERS;
3143     }
3144     
3145     /* Add all digests and ciphers */
3146     OpenSSL_add_all_algorithms();
3147     
3148     /* See which digests we have available and set max_ssf accordingly */
3149     opts = digest_options;
3150     while (opts->name) {
3151         if (EVP_get_digestbyname(opts->evp_name)) {
3152             opts->enabled = 1;
3153             
3154             srp_client_plugins[0].max_ssf = opts->ssf;
3155         }
3156         
3157         opts++;
3158     }
3159     
3160     /* See which ciphers we have available and set max_ssf accordingly */
3161     opts = cipher_options;
3162     while (opts->name) {
3163         if (EVP_get_cipherbyname(opts->evp_name)) {
3164             opts->enabled = 1;
3165             
3166             if (opts->ssf > srp_client_plugins[0].max_ssf) {
3167                 srp_client_plugins[0].max_ssf = opts->ssf;
3168             }
3169         }
3170         
3171         opts++;
3172     }
3173     
3174     *out_version = SASL_CLIENT_PLUG_VERSION;
3175     *pluglist = srp_client_plugins;
3176     *plugcount=1;
3177     
3178     return SASL_OK;
3179 }