gsasl  1.8.0
scram/parser.c
Go to the documentation of this file.
00001 /* parser.c --- SCRAM parser.
00002  * Copyright (C) 2009-2012 Simon Josefsson
00003  *
00004  * This file is part of GNU SASL Library.
00005  *
00006  * GNU SASL Library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public License
00008  * as published by the Free Software Foundation; either version 2.1 of
00009  * the License, or (at your option) any later version.
00010  *
00011  * GNU SASL Library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with GNU SASL Library; if not, write to the Free
00018  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019  * Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #ifdef HAVE_CONFIG_H
00024 #include "config.h"
00025 #endif
00026 
00027 /* Get prototypes. */
00028 #include "parser.h"
00029 
00030 /* Get malloc, free. */
00031 #include <stdlib.h>
00032 
00033 /* Get memcpy, strlen. */
00034 #include <string.h>
00035 
00036 /* Get validator. */
00037 #include "validate.h"
00038 
00039 /* Get c_isalpha. */
00040 #include "c-ctype.h"
00041 
00042 static char *
00043 unescape (const char *str, size_t len)
00044 {
00045   char *out = malloc (len + 1);
00046   char *p = out;
00047 
00048   if (!out)
00049     return NULL;
00050 
00051   while (len > 0 && *str)
00052     {
00053       if (len >= 3 && str[0] == '=' && str[1] == '2' && str[2] == 'C')
00054         {
00055           *p++ = ',';
00056           str += 3;
00057           len -= 3;
00058         }
00059       else if (len >= 3 && str[0] == '=' && str[1] == '3' && str[2] == 'D')
00060         {
00061           *p++ = '=';
00062           str += 3;
00063           len -= 3;
00064         }
00065       else
00066         {
00067           *p++ = *str;
00068           str++;
00069           len--;
00070         }
00071     }
00072   *p = '\0';
00073 
00074   return out;
00075 }
00076 
00077 int
00078 scram_parse_client_first (const char *str, size_t len,
00079                           struct scram_client_first *cf)
00080 {
00081   /* Minimum client first string is 'n,,n=a,r=b'. */
00082   if (strnlen (str, len) < 10)
00083     return -1;
00084 
00085   if (len == 0 || (*str != 'n' && *str != 'y' && *str != 'p'))
00086     return -1;
00087   cf->cbflag = *str;
00088   str++, len--;
00089 
00090   if (cf->cbflag == 'p')
00091     {
00092       const char *p;
00093 
00094       if (len == 0 || *str != '=')
00095         return -1;
00096       str++, len--;
00097 
00098       p = memchr (str, ',', len);
00099       if (!p)
00100         return -1;
00101       cf->cbname = malloc (p - str + 1);
00102       if (!cf->cbname)
00103         return -1;
00104       memcpy (cf->cbname, str, p - str);
00105       cf->cbname[p - str] = '\0';
00106       len -= (p - str);
00107       str += (p - str);
00108     }
00109 
00110   if (len == 0 || *str != ',')
00111     return -1;
00112   str++, len--;
00113 
00114   if (len == 0)
00115     return -1;
00116   if (*str == 'a')
00117     {
00118       const char *p;
00119       size_t l;
00120 
00121       str++, len--;
00122       if (len == 0 || *str != '=')
00123         return -1;
00124       str++, len--;
00125 
00126       p = memchr (str, ',', len);
00127       if (!p)
00128         return -1;
00129 
00130       l = p - str;
00131       if (len < l)
00132         return -1;
00133 
00134       cf->authzid = unescape (str, l);
00135       if (!cf->authzid)
00136         return -1;
00137 
00138       str = p;
00139       len -= l;
00140     }
00141 
00142   if (len == 0 || *str != ',')
00143     return -1;
00144   str++, len--;
00145 
00146   if (len == 0 || *str != 'n')
00147     return -1;
00148   str++, len--;
00149 
00150   if (len == 0 || *str != '=')
00151     return -1;
00152   str++, len--;
00153 
00154   {
00155     const char *p;
00156     size_t l;
00157 
00158     p = memchr (str, ',', len);
00159     if (!p)
00160       return -1;
00161 
00162     l = p - str;
00163     if (len < l)
00164       return -1;
00165 
00166     cf->username = unescape (str, l);
00167     if (!cf->username)
00168       return -1;
00169 
00170     str = p;
00171     len -= l;
00172   }
00173 
00174   if (len == 0 || *str != ',')
00175     return -1;
00176   str++, len--;
00177 
00178   if (len == 0 || *str != 'r')
00179     return -1;
00180   str++, len--;
00181 
00182   if (len == 0 || *str != '=')
00183     return -1;
00184   str++, len--;
00185 
00186   {
00187     const char *p;
00188     size_t l;
00189 
00190     p = memchr (str, ',', len);
00191     if (!p)
00192       p = str + len;
00193     if (!p)
00194       return -1;
00195 
00196     l = p - str;
00197     if (len < l)
00198       return -1;
00199 
00200     cf->client_nonce = malloc (l + 1);
00201     if (!cf->client_nonce)
00202       return -1;
00203 
00204     memcpy (cf->client_nonce, str, l);
00205     cf->client_nonce[l] = '\0';
00206 
00207     str = p;
00208     len -= l;
00209   }
00210 
00211   /* FIXME check that any extension fields follow valid syntax. */
00212 
00213   if (scram_valid_client_first (cf) < 0)
00214     return -1;
00215 
00216   return 0;
00217 }
00218 
00219 int
00220 scram_parse_server_first (const char *str, size_t len,
00221                           struct scram_server_first *sf)
00222 {
00223   /* Minimum server first string is 'r=ab,s=biws,i=1'. */
00224   if (strnlen (str, len) < 15)
00225     return -1;
00226 
00227   if (len == 0 || *str != 'r')
00228     return -1;
00229   str++, len--;
00230 
00231   if (len == 0 || *str != '=')
00232     return -1;
00233   str++, len--;
00234 
00235   {
00236     const char *p;
00237     size_t l;
00238 
00239     p = memchr (str, ',', len);
00240     if (!p)
00241       return -1;
00242 
00243     l = p - str;
00244     if (len < l)
00245       return -1;
00246 
00247     sf->nonce = malloc (l + 1);
00248     if (!sf->nonce)
00249       return -1;
00250 
00251     memcpy (sf->nonce, str, l);
00252     sf->nonce[l] = '\0';
00253 
00254     str = p;
00255     len -= l;
00256   }
00257 
00258   if (len == 0 || *str != ',')
00259     return -1;
00260   str++, len--;
00261 
00262   if (len == 0 || *str != 's')
00263     return -1;
00264   str++, len--;
00265 
00266   if (len == 0 || *str != '=')
00267     return -1;
00268   str++, len--;
00269 
00270   {
00271     const char *p;
00272     size_t l;
00273 
00274     p = memchr (str, ',', len);
00275     if (!p)
00276       return -1;
00277 
00278     l = p - str;
00279     if (len < l)
00280       return -1;
00281 
00282     sf->salt = malloc (l + 1);
00283     if (!sf->salt)
00284       return -1;
00285 
00286     memcpy (sf->salt, str, l);
00287     sf->salt[l] = '\0';
00288 
00289     str = p;
00290     len -= l;
00291   }
00292 
00293   if (len == 0 || *str != ',')
00294     return -1;
00295   str++, len--;
00296 
00297   if (len == 0 || *str != 'i')
00298     return -1;
00299   str++, len--;
00300 
00301   if (len == 0 || *str != '=')
00302     return -1;
00303   str++, len--;
00304 
00305   sf->iter = 0;
00306   for (; len > 0 && *str >= '0' && *str <= '9'; str++, len--)
00307     {
00308       size_t last_iter = sf->iter;
00309 
00310       sf->iter = sf->iter * 10 + (*str - '0');
00311 
00312       /* Protect against wrap arounds. */
00313       if (sf->iter < last_iter)
00314         return -1;
00315     }
00316 
00317   if (len > 0 && *str != ',')
00318     return -1;
00319 
00320   /* FIXME check that any extension fields follow valid syntax. */
00321 
00322   if (scram_valid_server_first (sf) < 0)
00323     return -1;
00324 
00325   return 0;
00326 }
00327 
00328 int
00329 scram_parse_client_final (const char *str, size_t len,
00330                           struct scram_client_final *cl)
00331 {
00332   /* Minimum client final string is 'c=biws,r=ab,p=ab=='. */
00333   if (strnlen (str, len) < 18)
00334     return -1;
00335 
00336   if (len == 0 || *str != 'c')
00337     return -1;
00338   str++, len--;
00339 
00340   if (len == 0 || *str != '=')
00341     return -1;
00342   str++, len--;
00343 
00344   {
00345     const char *p;
00346     size_t l;
00347 
00348     p = memchr (str, ',', len);
00349     if (!p)
00350       return -1;
00351 
00352     l = p - str;
00353     if (len < l)
00354       return -1;
00355 
00356     cl->cbind = malloc (l + 1);
00357     if (!cl->cbind)
00358       return -1;
00359 
00360     memcpy (cl->cbind, str, l);
00361     cl->cbind[l] = '\0';
00362 
00363     str = p;
00364     len -= l;
00365   }
00366 
00367   if (len == 0 || *str != ',')
00368     return -1;
00369   str++, len--;
00370 
00371   if (len == 0 || *str != 'r')
00372     return -1;
00373   str++, len--;
00374 
00375   if (len == 0 || *str != '=')
00376     return -1;
00377   str++, len--;
00378 
00379   {
00380     const char *p;
00381     size_t l;
00382 
00383     p = memchr (str, ',', len);
00384     if (!p)
00385       return -1;
00386 
00387     l = p - str;
00388     if (len < l)
00389       return -1;
00390 
00391     cl->nonce = malloc (l + 1);
00392     if (!cl->nonce)
00393       return -1;
00394 
00395     memcpy (cl->nonce, str, l);
00396     cl->nonce[l] = '\0';
00397 
00398     str = p;
00399     len -= l;
00400   }
00401 
00402   if (len == 0 || *str != ',')
00403     return -1;
00404   str++, len--;
00405 
00406   /* Ignore extensions. */
00407   while (len > 0 && c_isalpha (*str) && *str != 'p')
00408     {
00409       const char *p;
00410       size_t l;
00411 
00412       str++, len--;
00413 
00414       if (len == 0 || *str != '=')
00415         return -1;
00416       str++, len--;
00417 
00418       p = memchr (str, ',', len);
00419       if (!p)
00420         return -1;
00421       p++;
00422 
00423       l = p - str;
00424       if (len < l)
00425         return -1;
00426 
00427       str = p;
00428       len -= l;
00429     }
00430 
00431   if (len == 0 || *str != 'p')
00432     return -1;
00433   str++, len--;
00434 
00435   if (len == 0 || *str != '=')
00436     return -1;
00437   str++, len--;
00438 
00439   /* Sanity check proof. */
00440   if (memchr (str, '\0', len))
00441     return -1;
00442 
00443   cl->proof = malloc (len + 1);
00444   if (!cl->proof)
00445     return -1;
00446 
00447   memcpy (cl->proof, str, len);
00448   cl->proof[len] = '\0';
00449 
00450   if (scram_valid_client_final (cl) < 0)
00451     return -1;
00452 
00453   return 0;
00454 }
00455 
00456 int
00457 scram_parse_server_final (const char *str, size_t len,
00458                           struct scram_server_final *sl)
00459 {
00460   /* Minimum client final string is 'v=ab=='. */
00461   if (strnlen (str, len) < 6)
00462     return -1;
00463 
00464   if (len == 0 || *str != 'v')
00465     return -1;
00466   str++, len--;
00467 
00468   if (len == 0 || *str != '=')
00469     return -1;
00470   str++, len--;
00471 
00472   /* Sanity check proof. */
00473   if (memchr (str, '\0', len))
00474     return -1;
00475 
00476   sl->verifier = malloc (len + 1);
00477   if (!sl->verifier)
00478     return -1;
00479 
00480   memcpy (sl->verifier, str, len);
00481   sl->verifier[len] = '\0';
00482 
00483   if (scram_valid_server_final (sl) < 0)
00484     return -1;
00485 
00486   return 0;
00487 }