scram/parser.c

Go to the documentation of this file.
00001 /* parser.c --- SCRAM parser.
00002  * Copyright (C) 2009, 2010  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'))
00086       /* FIXME support channel bindings */
00087       return -1;
00088   cf->cbflag = *str;
00089   str++, len--;
00090 
00091   if (len == 0 || *str != ',')
00092     return -1;
00093   str++, len--;
00094 
00095   if (len == 0)
00096     return -1;
00097   if (*str == 'a')
00098     {
00099       const char *p;
00100       size_t l;
00101 
00102       str++, len--;
00103       if (len == 0 || *str != '=')
00104         return -1;
00105       str++, len--;
00106 
00107       p = memchr (str, ',', len);
00108       if (!p)
00109         return -1;
00110 
00111       l = p - str;
00112       if (len < l)
00113         return -1;
00114 
00115       cf->authzid = unescape (str, l);
00116       if (!cf->authzid)
00117         return -1;
00118 
00119       str = p;
00120       len -= l;
00121     }
00122 
00123   if (len == 0 || *str != ',')
00124     return -1;
00125   str++, len--;
00126 
00127   if (len == 0 || *str != 'n')
00128     return -1;
00129   str++, len--;
00130 
00131   if (len == 0 || *str != '=')
00132     return -1;
00133   str++, len--;
00134 
00135   {
00136     const char *p;
00137     size_t l;
00138 
00139     p = memchr (str, ',', len);
00140     if (!p)
00141       return -1;
00142 
00143     l = p - str;
00144     if (len < l)
00145       return -1;
00146 
00147     cf->username = unescape (str, l);
00148     if (!cf->username)
00149       return -1;
00150 
00151     str = p;
00152     len -= l;
00153   }
00154 
00155   if (len == 0 || *str != ',')
00156     return -1;
00157   str++, len--;
00158 
00159   if (len == 0 || *str != 'r')
00160     return -1;
00161   str++, len--;
00162 
00163   if (len == 0 || *str != '=')
00164     return -1;
00165   str++, len--;
00166 
00167   {
00168     const char *p;
00169     size_t l;
00170 
00171     p = memchr (str, ',', len);
00172     if (!p)
00173       p = str + len;
00174     if (!p)
00175       return -1;
00176 
00177     l = p - str;
00178     if (len < l)
00179       return -1;
00180 
00181     cf->client_nonce = malloc (l + 1);
00182     if (!cf->client_nonce)
00183       return -1;
00184 
00185     memcpy (cf->client_nonce, str, l);
00186     cf->client_nonce[l] = '\0';
00187 
00188     str = p;
00189     len -= l;
00190   }
00191 
00192   /* FIXME check that any extension fields follow valid syntax. */
00193 
00194   if (scram_valid_client_first (cf) < 0)
00195     return -1;
00196 
00197   return 0;
00198 }
00199 
00200 int
00201 scram_parse_server_first (const char *str, size_t len,
00202                           struct scram_server_first *sf)
00203 {
00204   /* Minimum server first string is 'r=ab,s=biws,i=1'. */
00205   if (strnlen (str, len) < 15)
00206     return -1;
00207 
00208   if (len == 0 || *str != 'r')
00209     return -1;
00210   str++, len--;
00211 
00212   if (len == 0 || *str != '=')
00213     return -1;
00214   str++, len--;
00215 
00216   {
00217     const char *p;
00218     size_t l;
00219 
00220     p = memchr (str, ',', len);
00221     if (!p)
00222       return -1;
00223 
00224     l = p - str;
00225     if (len < l)
00226       return -1;
00227 
00228     sf->nonce = malloc (l + 1);
00229     if (!sf->nonce)
00230       return -1;
00231 
00232     memcpy (sf->nonce, str, l);
00233     sf->nonce[l] = '\0';
00234 
00235     str = p;
00236     len -= l;
00237   }
00238 
00239   if (len == 0 || *str != ',')
00240     return -1;
00241   str++, len--;
00242 
00243   if (len == 0 || *str != 's')
00244     return -1;
00245   str++, len--;
00246 
00247   if (len == 0 || *str != '=')
00248     return -1;
00249   str++, len--;
00250 
00251   {
00252     const char *p;
00253     size_t l;
00254 
00255     p = memchr (str, ',', len);
00256     if (!p)
00257       return -1;
00258 
00259     l = p - str;
00260     if (len < l)
00261       return -1;
00262 
00263     sf->salt = malloc (l + 1);
00264     if (!sf->salt)
00265       return -1;
00266 
00267     memcpy (sf->salt, str, l);
00268     sf->salt[l] = '\0';
00269 
00270     str = p;
00271     len -= l;
00272   }
00273 
00274   if (len == 0 || *str != ',')
00275     return -1;
00276   str++, len--;
00277 
00278   if (len == 0 || *str != 'i')
00279     return -1;
00280   str++, len--;
00281 
00282   if (len == 0 || *str != '=')
00283     return -1;
00284   str++, len--;
00285 
00286   sf->iter = 0;
00287   for (; len > 0 && *str >= '0' && *str <= '9'; str++, len--)
00288     {
00289       size_t last_iter = sf->iter;
00290 
00291       sf->iter = sf->iter * 10 + (*str - '0');
00292 
00293       /* Protect against wrap arounds. */
00294       if (sf->iter < last_iter)
00295         return -1;
00296     }
00297 
00298   if (len > 0 && *str != ',')
00299     return -1;
00300 
00301   /* FIXME check that any extension fields follow valid syntax. */
00302 
00303   if (scram_valid_server_first (sf) < 0)
00304     return -1;
00305 
00306   return 0;
00307 }
00308 
00309 int
00310 scram_parse_client_final (const char *str, size_t len,
00311                           struct scram_client_final *cl)
00312 {
00313   /* Minimum client final string is 'c=biws,r=ab,p=ab=='. */
00314   if (strnlen (str, len) < 18)
00315     return -1;
00316 
00317   if (len == 0 || *str != 'c')
00318     return -1;
00319   str++, len--;
00320 
00321   if (len == 0 || *str != '=')
00322     return -1;
00323   str++, len--;
00324 
00325   {
00326     const char *p;
00327     size_t l;
00328 
00329     p = memchr (str, ',', len);
00330     if (!p)
00331       return -1;
00332 
00333     l = p - str;
00334     if (len < l)
00335       return -1;
00336 
00337     cl->cbind = malloc (l + 1);
00338     if (!cl->cbind)
00339       return -1;
00340 
00341     memcpy (cl->cbind, str, l);
00342     cl->cbind[l] = '\0';
00343 
00344     str = p;
00345     len -= l;
00346   }
00347 
00348   if (len == 0 || *str != ',')
00349     return -1;
00350   str++, len--;
00351 
00352   if (len == 0 || *str != 'r')
00353     return -1;
00354   str++, len--;
00355 
00356   if (len == 0 || *str != '=')
00357     return -1;
00358   str++, len--;
00359 
00360   {
00361     const char *p;
00362     size_t l;
00363 
00364     p = memchr (str, ',', len);
00365     if (!p)
00366       return -1;
00367 
00368     l = p - str;
00369     if (len < l)
00370       return -1;
00371 
00372     cl->nonce = malloc (l + 1);
00373     if (!cl->nonce)
00374       return -1;
00375 
00376     memcpy (cl->nonce, str, l);
00377     cl->nonce[l] = '\0';
00378 
00379     str = p;
00380     len -= l;
00381   }
00382 
00383   if (len == 0 || *str != ',')
00384     return -1;
00385   str++, len--;
00386 
00387   /* Ignore extensions. */
00388   while (len > 0 && c_isalpha (*str) && *str != 'p')
00389     {
00390       const char *p;
00391       size_t l;
00392 
00393       str++, len--;
00394 
00395       if (len == 0 || *str != '=')
00396         return -1;
00397       str++, len--;
00398 
00399       p = memchr (str, ',', len);
00400       if (!p)
00401         return -1;
00402       p++;
00403 
00404       l = p - str;
00405       if (len < l)
00406         return -1;
00407 
00408       str = p;
00409       len -= l;
00410     }
00411 
00412   if (len == 0 || *str != 'p')
00413     return -1;
00414   str++, len--;
00415 
00416   if (len == 0 || *str != '=')
00417     return -1;
00418   str++, len--;
00419 
00420   /* Sanity check proof. */
00421   if (memchr (str, '\0', len))
00422     return -1;
00423 
00424   cl->proof = malloc (len + 1);
00425   if (!cl->proof)
00426     return -1;
00427 
00428   memcpy (cl->proof, str, len);
00429   cl->proof[len] = '\0';
00430 
00431   if (scram_valid_client_final (cl) < 0)
00432     return -1;
00433 
00434   return 0;
00435 }
00436 
00437 int
00438 scram_parse_server_final (const char *str, size_t len,
00439                           struct scram_server_final *sl)
00440 {
00441   /* Minimum client final string is 'v=ab=='. */
00442   if (strnlen (str, len) < 6)
00443     return -1;
00444 
00445   if (len == 0 || *str != 'v')
00446     return -1;
00447   str++, len--;
00448 
00449   if (len == 0 || *str != '=')
00450     return -1;
00451   str++, len--;
00452 
00453   /* Sanity check proof. */
00454   if (memchr (str, '\0', len))
00455     return -1;
00456 
00457   sl->verifier = malloc (len + 1);
00458   if (!sl->verifier)
00459     return -1;
00460 
00461   memcpy (sl->verifier, str, len);
00462   sl->verifier[len] = '\0';
00463 
00464   if (scram_valid_server_final (sl) < 0)
00465     return -1;
00466 
00467   return 0;
00468 }