📄 mech_digest_md5.c
字号:
/* * scod - a minimal sasl implementation for jabberd2 * Copyright (c) 2003 Robert Norris * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA *//* DIGEST-MD5 mechanism */#include "scod.h"#include <ctype.h>#define HT (9)#define CR (13)#define LF (10)#define SP (32)#define DEL (127)static char *_opt_quote(char *in) { int nesc; char *r, *out, *w; r = in; nesc = 0; while(*r != '\0') { if(*r == '"' || *r == '\\') nesc++; r++; } out = (char *) malloc(sizeof(char) * (strlen(in) + nesc + 3)); r = in; w = out; *w = '"'; w++; while(*r != '\0') { if(*r == '"' || *r == '\\') { *w = '\\'; w++; } *w = *r; w++; r++; } *w = '"'; w++; *w = '\0'; log_debug(ZONE, "escaped '%s' into '%s'", in, out); return out;}/** the list parser is based on code from cyrus-sasl. I love open source ;) */static char *_opt_skip_lws(char *c) { if(c == NULL) return NULL; while(*c == ' ' || *c == HT || *c == CR || *c == LF) { if(*c == '\0') break; c++; } return c;}static char *_opt_skip_token(char *c, int ci) { if(c == NULL) return NULL; while(*c > SP) { if(*c == DEL || *c == '(' || *c == ')' || *c == '<' || *c == '>' || *c == '@' || *c == ',' || *c == ';' || *c == ':' || *c == '\\' || *c == '\'' || *c == '/' || *c == '[' || *c == ']' || *c == '?' || *c == '=' || *c == '{' || *c == '}') { if(ci) { if(!isupper((unsigned char) *c)) break; } else break; } c++; } return c;}static char *_opt_unquote(char *in) { char *out, *end; int esc = 0; /* if its not quoted, there's nothing to do */ if(*in != '"') return _opt_skip_token(in, 0); in++; out = in; for(end = in; *end != '\0'; end++, out++) { if(esc) { *out = *end; esc = 0; } else if(*end == '\\') { esc = 1; out--; } else if(*end == '"') break; else *out = *end; } if(*end != '"') return NULL; while(out <= end) { *out = '\0'; out++; } end++; return end; } static void _opt_get_pair(char **in, char **key, char **val) { char *end, *cur = *in; *key = NULL; *val = NULL; if(*cur == '\0') return; cur = _opt_skip_lws(cur); *key = cur; cur = _opt_skip_token(cur, 1); if(*cur != '=' && *cur != '\0') { *cur = '\0'; cur++; } cur = _opt_skip_lws(cur); if(*cur != '=') { *key = NULL; return; } *cur = '\0'; cur++; cur = _opt_skip_lws(cur); *val = (*cur == '"') ? cur + 1 : cur; end = _opt_unquote(cur); if(end == NULL) { *key = NULL; return; } if(*end != ',' && *end != '\0') { *end = '\0'; end++; } end = _opt_skip_lws(end); if(*end == ',') { *end = '\0'; end++; } else if(*end != '\0') { *key = NULL; return; } *in = end;}static xht _digest_md5_parse_options(const char *buf, int buflen) { xht hash, sub; char *nbuf, *in, *key, *val; nbuf = (char *) malloc(sizeof(char) * (buflen + 1)); strncpy(nbuf, buf, buflen); nbuf[buflen] = '\0'; hash = xhash_new(101); in = nbuf; while(1) { _opt_get_pair(&in, &key, &val); if(key == NULL) break; sub = xhash_get(hash, key); if(sub == NULL) { sub = xhash_new(11); xhash_put(hash, pstrdup(xhash_pool(hash), key), sub); pool_cleanup(xhash_pool(hash), (void (*)(void *)) xhash_free, sub); } xhash_put(sub, pstrdup(xhash_pool(hash), val), (void *) 1); log_debug(ZONE, "got key '%s' val '%s'", key, val); } free(nbuf); return hash;}static char *_digest_md5_gen_nonce(void) { int i, r; char nonce[65], hnonce[41]; for(i = 0; i < 64; i++) { r = (int) (36.0 * rand() / RAND_MAX); nonce[i] = (r >= 0 && r <= 9) ? (r + 48) : (r + 87); } nonce[64] = '\0'; shahash_r(nonce, hnonce); log_debug(ZONE, "generated nonce: %s", hnonce); return strdup(hnonce);}typedef struct _digest_md5_st { pool p; char *nonce; char *cnonce; char *nc; int step;} *digest_md5_t;static int _digest_md5_client_start(scod_mech_t mech, scod_t sd, char **resp, int *resplen) { log_debug(ZONE, "DIGEST-MD5 client start"); return sd_CONTINUE;}static int _digest_md5_client_step(scod_mech_t mech, scod_t sd, const char *chal, int challen, char **resp, int *resplen) { xht attrs, sub; char *key, *realm, *nonce, *qop, *charset, *algorithm, *cnonce, *c; md5_state_t md5; md5_byte_t hash[16]; char ha1[33], ha2[33], hrsp[33]; pool p; spool s; log_debug(ZONE, "DIGEST-MD5 client step; challenge: %.*s", challen, chal); if(sd->mech_data != NULL) { /* !!! check rspauth */ sd->mech_data = NULL; return sd_SUCCESS; } realm = nonce = qop = charset = algorithm = NULL; attrs = _digest_md5_parse_options(chal, challen); if(xhash_iter_first(attrs)) do { xhash_iter_get(attrs, (const char **) &key, (void **) &sub); log_debug(ZONE, "extracting '%s'", key); if(xhash_iter_first(sub)) { if(strcmp(key, "realm") == 0) (mech->ctx->cb)(sd, sd_cb_DIGEST_MD5_CHOOSE_REALM, (void *) sub, (void **) &realm, mech->ctx->cbarg); else if(strcmp(key, "nonce") == 0) xhash_iter_get(sub, (const char **) &nonce, NULL); else if(strcmp(key, "qop") == 0) xhash_iter_get(sub, (const char **) &qop, NULL); else if(strcmp(key, "charset") == 0) xhash_iter_get(sub, (const char **) &charset, NULL); else if(strcmp(key, "algorithm") == 0) xhash_iter_get(sub, (const char **) &algorithm, NULL); } } while(xhash_iter_next(attrs)); if(nonce == NULL || qop == NULL || charset == NULL || algorithm == NULL) { log_debug(ZONE, "missing attribute"); xhash_free(attrs); return sd_auth_MALFORMED_DATA; } cnonce = _digest_md5_gen_nonce(); md5_init(&md5); md5_append(&md5, sd->authnid, strlen(sd->authnid)); md5_append(&md5, ":", 1); if(realm != NULL) md5_append(&md5, realm, strlen(realm)); md5_append(&md5, ":", 1); md5_append(&md5, sd->pass, strlen(sd->pass)); md5_finish(&md5, hash); md5_init(&md5); md5_append(&md5, hash, 16); md5_append(&md5, ":", 1); md5_append(&md5, nonce, strlen(nonce)); md5_append(&md5, ":", 1); md5_append(&md5, cnonce, 40); if(sd->authzid != NULL) { md5_append(&md5, ":", 1); md5_append(&md5, sd->authzid, strlen(sd->authzid)); } md5_finish(&md5, hash); /* A1 */ hex_from_raw(hash, 16, ha1); log_debug(ZONE, "HEX(H(A1)) = %s", ha1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -