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