|
gsasl
1.8.0
|
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 }
1.7.6.1