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