summaryrefslogtreecommitdiffstats
path: root/auth.c
diff options
context:
space:
mode:
Diffstat (limited to 'auth.c')
-rw-r--r--auth.c826
1 files changed, 826 insertions, 0 deletions
diff --git a/auth.c b/auth.c
new file mode 100644
index 0000000..d3ac1e0
--- /dev/null
+++ b/auth.c
@@ -0,0 +1,826 @@
+/*
+ * Authentication helper functions.
+ *
+ * Copyright (C) 2014 Andreas Steinmetz <ast@domdv.de>
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <string.h>
+#include <stdint.h>
+#include "auth.h"
+
+#define MD5_SIZE 16
+#define MD5_HEX (MD5_SIZE<<1)
+#define MD5(a) uint8_t a[MD5_SIZE]
+
+#define AUTH_SESS 0x13
+#define AUTH_SESS_REPLY 0x14
+
+#define AUTH_SUCCESS 0x00
+#define AUTH_FAIL 0x01
+
+#define TYPE_METHODS 0x00
+#define TYPE_PLAIN 0x01
+#define TYPE_RFC2069 0x03
+#define TYPE_RFC2617 0x04
+
+#define MAX_USER 32
+#define MAX_PASS 32
+#define MAX_REALM 64
+#define MAX_NONCE MD5_HEX
+#define MAX_CNONCE MD5_HEX
+#define MAX_RESPONSE MD5_HEX
+#define MAX_QOP 8
+
+#define URI "/RedirectionService"
+#define NC "00000002"
+#define QOP "auth"
+#define METHOD "POST"
+
+#define put_header(data,length,type) \
+do { \
+ *data++=AUTH_SESS; \
+ *data++=AUTH_SUCCESS; \
+ *data++=0; \
+ *data++=0; \
+ *data++=type; \
+ *data++=(unsigned char)(length); \
+ *data++=(unsigned char)(length>>8); \
+ *data++=(unsigned char)(length>>16); \
+ *data++=(unsigned char)(length>>24); \
+} while(0)
+
+#define put_element(data,element) \
+do { \
+ int length=strlen(element); \
+ *data++=(unsigned char)length; \
+ memcpy(data,element,length); \
+ data+=length; \
+} while(0)
+
+#define get_header(data,len,method,status) \
+do { \
+ if(data[0]!=AUTH_SESS_REPLY)goto out; \
+ status=data[1]; \
+ if(data[4]!=method)goto out; \
+ len=data[8]; \
+ len<<=8; \
+ len|=data[7]; \
+ len<<=8; \
+ len|=data[6]; \
+ len<<=8; \
+ len|=data[5]; \
+} while(0)
+
+#define get_element(data,len,element,max) \
+do { \
+ int blen=*data++; \
+ if(blen>--len||blen>max)goto out; \
+ memcpy(element,data,blen); \
+ element[blen]=0; \
+ data+=blen; \
+ len-=blen; \
+} while(0)
+
+typedef struct
+{
+ uint32_t md5[4];
+ uint32_t total;
+ uint8_t bfr[64];
+ uint8_t size;
+} md5_ctx;
+
+static void md5block(uint32_t *md5,uint8_t *block)
+{
+ register uint32_t a;
+ register uint32_t b;
+ register uint32_t c;
+ register uint32_t d;
+ uint32_t bfr[16];
+
+ a=block[3];
+ a<<=8;
+ a+=block[2];
+ a<<=8;
+ a+=block[1];
+ a<<=8;
+ bfr[0]=a+block[0];
+
+ a=block[7];
+ a<<=8;
+ a+=block[6];
+ a<<=8;
+ a+=block[5];
+ a<<=8;
+ bfr[1]=a+block[4];
+
+ a=block[11];
+ a<<=8;
+ a+=block[10];
+ a<<=8;
+ a+=block[9];
+ a<<=8;
+ bfr[2]=a+block[8];
+
+ a=block[15];
+ a<<=8;
+ a+=block[14];
+ a<<=8;
+ a+=block[13];
+ a<<=8;
+ bfr[3]=a+block[12];
+
+ a=block[19];
+ a<<=8;
+ a+=block[18];
+ a<<=8;
+ a+=block[17];
+ a<<=8;
+ bfr[4]=a+block[16];
+
+ a=block[23];
+ a<<=8;
+ a+=block[22];
+ a<<=8;
+ a+=block[21];
+ a<<=8;
+ bfr[5]=a+block[20];
+
+ a=block[27];
+ a<<=8;
+ a+=block[26];
+ a<<=8;
+ a+=block[25];
+ a<<=8;
+ bfr[6]=a+block[24];
+
+ a=block[31];
+ a<<=8;
+ a+=block[30];
+ a<<=8;
+ a+=block[29];
+ a<<=8;
+ bfr[7]=a+block[28];
+
+ a=block[35];
+ a<<=8;
+ a+=block[34];
+ a<<=8;
+ a+=block[33];
+ a<<=8;
+ bfr[8]=a+block[32];
+
+ a=block[39];
+ a<<=8;
+ a+=block[38];
+ a<<=8;
+ a+=block[37];
+ a<<=8;
+ bfr[9]=a+block[36];
+
+ a=block[43];
+ a<<=8;
+ a+=block[42];
+ a<<=8;
+ a+=block[41];
+ a<<=8;
+ bfr[10]=a+block[40];
+
+ a=block[47];
+ a<<=8;
+ a+=block[46];
+ a<<=8;
+ a+=block[45];
+ a<<=8;
+ bfr[11]=a+block[44];
+
+ a=block[51];
+ a<<=8;
+ a+=block[50];
+ a<<=8;
+ a+=block[49];
+ a<<=8;
+ bfr[12]=a+block[48];
+
+ a=block[55];
+ a<<=8;
+ a+=block[54];
+ a<<=8;
+ a+=block[53];
+ a<<=8;
+ bfr[13]=a+block[52];
+
+ a=block[59];
+ a<<=8;
+ a+=block[58];
+ a<<=8;
+ a+=block[57];
+ a<<=8;
+ bfr[14]=a+block[56];
+
+ a=block[63];
+ a<<=8;
+ a+=block[62];
+ a<<=8;
+ a+=block[61];
+ a<<=8;
+ bfr[15]=a+block[60];
+
+ a=md5[0];
+ b=md5[1];
+ c=md5[2];
+ d=md5[3];
+
+ a+=bfr[0];
+ a+=0xd76aa478;
+ a+=d^(b&(c^d));
+ a=(a<<7)|(a>>25);
+ a+=b;
+ d+=bfr[1];
+ d+=0xe8c7b756;
+ d+=c^(a&(b^c));
+ d=(d<<12)|(d>>20);
+ d+=a;
+ c+=bfr[2];
+ c+=0x242070db;
+ c+=b^(d&(a^b));
+ c=(c<<17)|(c>>15);
+ c+=d;
+ b+=bfr[3];
+ b+=0xc1bdceee;
+ b+=a^(c&(d^a));
+ b=(b<<22)|(b>>10);
+ b+=c;
+ a+=bfr[4];
+ a+=0xf57c0faf;
+ a+=d^(b&(c^d));
+ a=(a<<7)|(a>>25);
+ a+=b;
+ d+=bfr[5];
+ d+=0x4787c62a;
+ d+=c^(a&(b^c));
+ d=(d<<12)|(d>>20);
+ d+=a;
+ c+=bfr[6];
+ c+=0xa8304613;
+ c+=b^(d&(a^b));
+ c=(c<<17)|(c>>15);
+ c+=d;
+ b+=bfr[7];
+ b+=0xfd469501;
+ b+=a^(c&(d^a));
+ b=(b<<22)|(b>>10);
+ b+=c;
+ a+=bfr[8];
+ a+=0x698098d8;
+ a+=d^(b&(c^d));
+ a=(a<<7)|(a>>25);
+ a+=b;
+ d+=bfr[9];
+ d+=0x8b44f7af;
+ d+=c^(a&(b^c));
+ d=(d<<12)|(d>>20);
+ d+=a;
+ c+=bfr[10];
+ c+=0xffff5bb1;
+ c+=b^(d&(a^b));
+ c=(c<<17)|(c>>15);
+ c+=d;
+ b+=bfr[11];
+ b+=0x895cd7be;
+ b+=a^(c&(d^a));
+ b=(b<<22)|(b>>10);
+ b+=c;
+ a+=bfr[12];
+ a+=0x6b901122;
+ a+=d^(b&(c^d));
+ a=(a<<7)|(a>>25);
+ a+=b;
+ d+=bfr[13];
+ d+=0xfd987193;
+ d+=c^(a&(b^c));
+ d=(d<<12)|(d>>20);
+ d+=a;
+ c+=bfr[14];
+ c+=0xa679438e;
+ c+=b^(d&(a^b));
+ c=(c<<17)|(c>>15);
+ c+=d;
+ b+=bfr[15];
+ b+=0x49b40821;
+ b+=a^(c&(d^a));
+ b=(b<<22)|(b>>10);
+ b+=c;
+
+ a+=bfr[1];
+ a+=0xf61e2562;
+ a+=c^(d&(b^c));
+ a=(a<<5)|(a>>27);
+ a+=b;
+ d+=bfr[6];
+ d+=0xc040b340;
+ d+=b^(c&(a^b));
+ d=(d<<9)|(d>>23);
+ d+=a;
+ c+=bfr[11];
+ c+=0x265e5a51;
+ c+=a^(b&(d^a));
+ c=(c<<14)|(c>>18);
+ c+=d;
+ b+=bfr[0];
+ b+=0xe9b6c7aa;
+ b+=d^(a&(c^d));
+ b=(b<<20)|(b>>12);
+ b+=c;
+ a+=bfr[5];
+ a+=0xd62f105d;
+ a+=c^(d&(b^c));
+ a=(a<<5)|(a>>27);
+ a+=b;
+ d+=bfr[10];
+ d+=0x02441453;
+ d+=b^(c&(a^b));
+ d=(d<<9)|(d>>23);
+ d+=a;
+ c+=bfr[15];
+ c+=0xd8a1e681;
+ c+=a^(b&(d^a));
+ c=(c<<14)|(c>>18);
+ c+=d;
+ b+=bfr[4];
+ b+=0xe7d3fbc8;
+ b+=d^(a&(c^d));
+ b=(b<<20)|(b>>12);
+ b+=c;
+ a+=bfr[9];
+ a+=0x21e1cde6;
+ a+=c^(d&(b^c));
+ a=(a<<5)|(a>>27);
+ a+=b;
+ d+=bfr[14];
+ d+=0xc33707d6;
+ d+=b^(c&(a^b));
+ d=(d<<9)|(d>>23);
+ d+=a;
+ c+=bfr[3];
+ c+=0xf4d50d87;
+ c+=a^(b&(d^a));
+ c=(c<<14)|(c>>18);
+ c+=d;
+ b+=bfr[8];
+ b+=0x455a14ed;
+ b+=d^(a&(c^d));
+ b=(b<<20)|(b>>12);
+ b+=c;
+ a+=bfr[13];
+ a+=0xa9e3e905;
+ a+=c^(d&(b^c));
+ a=(a<<5)|(a>>27);
+ a+=b;
+ d+=bfr[2];
+ d+=0xfcefa3f8;
+ d+=b^(c&(a^b));
+ d=(d<<9)|(d>>23);
+ d+=a;
+ c+=bfr[7];
+ c+=0x676f02d9;
+ c+=a^(b&(d^a));
+ c=(c<<14)|(c>>18);
+ c+=d;
+ b+=bfr[12];
+ b+=0x8d2a4c8a;
+ b+=d^(a&(c^d));
+ b=(b<<20)|(b>>12);
+ b+=c;
+
+ a+=bfr[5];
+ a+=0xfffa3942;
+ a+=b^c^d;
+ a=(a<<4)|(a>>28);
+ a+=b;
+ d+=bfr[8];
+ d+=0x8771f681;
+ d+=a^b^c;
+ d=(d<<11)|(d>>21);
+ d+=a;
+ c+=bfr[11];
+ c+=0x6d9d6122;
+ c+=d^a^b;
+ c=(c<<16)|(c>>16);
+ c+=d;
+ b+=bfr[14];
+ b+=0xfde5380c;
+ b+=c^d^a;
+ b=(b<<23)|(b>>9);
+ b+=c;
+ a+=bfr[1];
+ a+=0xa4beea44;
+ a+=b^c^d;
+ a=(a<<4)|(a>>28);
+ a+=b;
+ d+=bfr[4];
+ d+=0x4bdecfa9;
+ d+=a^b^c;
+ d=(d<<11)|(d>>21);
+ d+=a;
+ c+=bfr[7];
+ c+=0xf6bb4b60;
+ c+=d^a^b;
+ c=(c<<16)|(c>>16);
+ c+=d;
+ b+=bfr[10];
+ b+=0xbebfbc70;
+ b+=c^d^a;
+ b=(b<<23)|(b>>9);
+ b+=c;
+ a+=bfr[13];
+ a+=0x289b7ec6;
+ a+=b^c^d;
+ a=(a<<4)|(a>>28);
+ a+=b;
+ d+=bfr[0];
+ d+=0xeaa127fa;
+ d+=a^b^c;
+ d=(d<<11)|(d>>21);
+ d+=a;
+ c+=bfr[3];
+ c+=0xd4ef3085;
+ c+=d^a^b;
+ c=(c<<16)|(c>>16);
+ c+=d;
+ b+=bfr[6];
+ b+=0x04881d05;
+ b+=c^d^a;
+ b=(b<<23)|(b>>9);
+ b+=c;
+ a+=bfr[9];
+ a+=0xd9d4d039;
+ a+=b^c^d;
+ a=(a<<4)|(a>>28);
+ a+=b;
+ d+=bfr[12];
+ d+=0xe6db99e5;
+ d+=a^b^c;
+ d=(d<<11)|(d>>21);
+ d+=a;
+ c+=bfr[15];
+ c+=0x1fa27cf8;
+ c+=d^a^b;
+ c=(c<<16)|(c>>16);
+ c+=d;
+ b+=bfr[2];
+ b+=0xc4ac5665;
+ b+=c^d^a;
+ b=(b<<23)|(b>>9);
+ b+=c;
+
+ a+=bfr[0];
+ a+=0xf4292244;
+ a+=c^(b|~d);
+ a=(a<<6)|(a>>26);
+ a+=b;
+ d+=bfr[7];
+ d+=0x432aff97;
+ d+=b^(a|~c);
+ d=(d<<10)|(d>>22);
+ d+=a;
+ c+=bfr[14];
+ c+=0xab9423a7;
+ c+=a^(d|~b);
+ c=(c<<15)|(c>>17);
+ c+=d;
+ b+=bfr[5];
+ b+=0xfc93a039;
+ b+=d^(c|~a);
+ b=(b<<21)|(b>>11);
+ b+=c;
+ a+=bfr[12];
+ a+=0x655b59c3;
+ a+=c^(b|~d);
+ a=(a<<6)|(a>>26);
+ a+=b;
+ d+=bfr[3];
+ d+=0x8f0ccc92;
+ d+=b^(a|~c);
+ d=(d<<10)|(d>>22);
+ d+=a;
+ c+=bfr[10];
+ c+=0xffeff47d;
+ c+=a^(d|~b);
+ c=(c<<15)|(c>>17);
+ c+=d;
+ b+=bfr[1];
+ b+=0x85845dd1;
+ b+=d^(c|~a);
+ b=(b<<21)|(b>>11);
+ b+=c;
+ a+=bfr[8];
+ a+=0x6fa87e4f;
+ a+=c^(b|~d);
+ a=(a<<6)|(a>>26);
+ a+=b;
+ d+=bfr[15];
+ d+=0xfe2ce6e0;
+ d+=b^(a|~c);
+ d=(d<<10)|(d>>22);
+ d+=a;
+ c+=bfr[6];
+ c+=0xa3014314;
+ c+=a^(d|~b);
+ c=(c<<15)|(c>>17);
+ c+=d;
+ b+=bfr[13];
+ b+=0x4e0811a1;
+ b+=d^(c|~a);
+ b=(b<<21)|(b>>11);
+ b+=c;
+ a+=bfr[4];
+ a+=0xf7537e82;
+ a+=c^(b|~d);
+ a=(a<<6)|(a>>26);
+ a+=b;
+ d+=bfr[11];
+ d+=0xbd3af235;
+ d+=b^(a|~c);
+ d=(d<<10)|(d>>22);
+ d+=a;
+ c+=bfr[2];
+ c+=0x2ad7d2bb;
+ c+=a^(d|~b);
+ c=(c<<15)|(c>>17);
+ c+=d;
+ b+=bfr[9];
+ b+=0xeb86d391;
+ b+=d^(c|~a);
+ b=(b<<21)|(b>>11);
+ b+=c;
+
+ md5[0]+=a;
+ md5[1]+=b;
+ md5[2]+=c;
+ md5[3]+=d;
+}
+
+static void md5init(register md5_ctx *ptr)
+{
+ ptr->total=ptr->size=0;
+ ptr->md5[0]=0x67452301;
+ ptr->md5[1]=0xefcdab89;
+ ptr->md5[2]=0x98badcfe;
+ ptr->md5[3]=0x10325476;
+}
+
+static void md5next(register uint8_t *data,register uint32_t length,
+ register md5_ctx *ptr)
+{
+ register uint32_t i;
+
+ ptr->total+=length;
+
+ for(i=ptr->size;(i&63)&&length;length--)ptr->bfr[i++]=*data++;
+
+ if(i==64)
+ {
+ i=0;
+ md5block(ptr->md5,ptr->bfr);
+ }
+
+ for(;length>63;data+=64,length-=64)
+ md5block(ptr->md5,data);
+
+ for(;length;length--)ptr->bfr[i++]=*data++;
+
+ ptr->size=(uint8_t)(i);
+}
+
+static void md5end(register uint8_t *result,register md5_ctx *ptr)
+{
+ register uint32_t i=ptr->size;
+
+ ptr->bfr[i++]=0x80;
+ if(i>56)
+ {
+ for(;i<64;i++)ptr->bfr[i]=0;
+ i=0;
+ md5block(ptr->md5,ptr->bfr);
+ }
+ for(;i<56;i++)ptr->bfr[i]=0;
+
+ ptr->bfr[56]=(uint8_t)((ptr->total)<<3);
+ ptr->bfr[57]=(uint8_t)((ptr->total)>>5);
+ ptr->bfr[58]=(uint8_t)((ptr->total)>>13);
+ ptr->bfr[59]=(uint8_t)((ptr->total)>>21);
+ ptr->bfr[60]=(uint8_t)((ptr->total)>>29);
+ ptr->bfr[61]=0;
+ ptr->bfr[62]=0;
+ ptr->bfr[63]=0;
+
+ md5block(ptr->md5,ptr->bfr);
+
+ result[ 0]=(uint8_t) (ptr->md5[0]);
+ result[ 1]=(uint8_t)((ptr->md5[0])>>8);
+ result[ 2]=(uint8_t)((ptr->md5[0])>>16);
+ result[ 3]=(uint8_t)((ptr->md5[0])>>24);
+ result[ 4]=(uint8_t) (ptr->md5[1]);
+ result[ 5]=(uint8_t)((ptr->md5[1])>>8);
+ result[ 6]=(uint8_t)((ptr->md5[1])>>16);
+ result[ 7]=(uint8_t)((ptr->md5[1])>>24);
+ result[ 8]=(uint8_t) (ptr->md5[2]);
+ result[ 9]=(uint8_t)((ptr->md5[2])>>8);
+ result[10]=(uint8_t)((ptr->md5[2])>>16);
+ result[11]=(uint8_t)((ptr->md5[2])>>24);
+ result[12]=(uint8_t) (ptr->md5[3]);
+ result[13]=(uint8_t)((ptr->md5[3])>>8);
+ result[14]=(uint8_t)((ptr->md5[3])>>16);
+ result[15]=(uint8_t)((ptr->md5[3])>>24);
+}
+
+static void bin2hex(unsigned char *bin,int len,char *hex)
+{
+ while(len--)
+ {
+ *hex=*bin>>4;
+ if(*hex>9)*hex+++='a'-10;
+ else *hex+++='0';
+ *hex=*bin++&0xf;
+ if(*hex>9)*hex+++='a'-10;
+ else *hex+++='0';
+ }
+ *hex=0;
+}
+
+int authenticate(int mode,char *user,char *pass,
+ int (*io)(void *parm,unsigned char *data,int len,int mode),void *parm)
+{
+ int r=-1;
+ int len;
+ int status;
+ int method;
+ unsigned char *ptr;
+ unsigned char bfr[512];
+ char realm[MAX_REALM+1];
+ char nonce[MAX_NONCE+1];
+ char cnonce[MAX_CNONCE+1];
+ char response[MAX_RESPONSE+1];
+ char qop[MAX_QOP+1];
+ char tmp[MD5_HEX+1];
+ MD5(md5);
+ md5_ctx ctx;
+
+ if(strlen(user)>MAX_USER||strlen(pass)>MAX_PASS)return -1;
+
+ ptr=bfr;
+ put_header(ptr,0,TYPE_METHODS);
+ if(io(parm,bfr,9,WRITE))goto out;
+
+ if(io(parm,bfr,9,READ))goto out;
+ get_header(bfr,len,TYPE_METHODS,status);
+ if(status!=AUTH_SUCCESS)goto out;
+ if(len>sizeof(bfr))goto out;
+ if(io(parm,bfr,len,READ))goto out;
+
+ for(method=0,ptr=bfr;len;len--)
+ {
+ if(!*ptr||*ptr>=sizeof(method)*8)return -1;
+ method|=1<<*ptr++;
+ }
+
+ if(method&(1<<TYPE_RFC2617))method=TYPE_RFC2617;
+ else if(method&(1<<TYPE_RFC2069))method=TYPE_RFC2069;
+ else if(method&(1<<TYPE_PLAIN))method=TYPE_PLAIN;
+ else goto out;
+
+ switch(method)
+ {
+ case TYPE_PLAIN:
+ len=strlen(user)+strlen(pass)+2;
+ ptr=bfr;
+ put_header(ptr,len,method);
+ put_element(ptr,user);
+ put_element(ptr,pass);
+ break;
+
+ case TYPE_RFC2069:
+ case TYPE_RFC2617:
+ len=strlen(user)+strlen(URI)+(method==TYPE_RFC2617?8:7);
+ ptr=bfr;
+ put_header(ptr,len,method);
+ put_element(ptr,user);
+ *ptr++=0;
+ *ptr++=0;
+ put_element(ptr,URI);
+ *ptr++=0;
+ *ptr++=0;
+ *ptr++=0;
+ *ptr=0;
+ if(io(parm,bfr,len+9,WRITE))goto out;
+
+ if(io(parm,bfr,9,READ))goto out;
+ get_header(bfr,len,method,status);
+ if(status!=AUTH_FAIL)goto out;
+ if(len>sizeof(bfr))goto out;
+ if(io(parm,bfr,len,READ))goto out;
+ ptr=bfr;
+ if(!len)goto out;
+ get_element(ptr,len,realm,MAX_REALM);
+ if(!len)goto out;
+ get_element(ptr,len,nonce,MAX_NONCE);
+ if(!len)*qop=0;
+ else get_element(ptr,len,qop,MAX_QOP);
+
+ if(method==TYPE_RFC2617)
+ {
+ if(strcmp(qop,QOP))goto out;
+ }
+ else if(*qop)goto out;
+
+ if(io(parm,bfr,16,RANDOM))goto out;
+ md5init(&ctx);
+ md5next(bfr,16,&ctx);
+ md5end(md5,&ctx);
+ bin2hex(md5,MD5_SIZE,cnonce);
+
+ md5init(&ctx);
+ md5next((uint8_t *)user,strlen(user),&ctx);
+ md5next((uint8_t *)":",1,&ctx);
+ md5next((uint8_t *)realm,strlen(realm),&ctx);
+ md5next((uint8_t *)":",1,&ctx);
+ md5next((uint8_t *)pass,strlen(pass),&ctx);
+ md5end(md5,&ctx);
+ bin2hex(md5,MD5_SIZE,tmp);
+
+ md5init(&ctx);
+ md5next((uint8_t *)METHOD,strlen(METHOD),&ctx);
+ md5next((uint8_t *)":",1,&ctx);
+ md5next((uint8_t *)URI,strlen(URI),&ctx);
+ md5end(md5,&ctx);
+ bin2hex(md5,MD5_SIZE,response);
+
+ md5init(&ctx);
+ md5next((uint8_t *)tmp,strlen(tmp),&ctx);
+ md5next((uint8_t *)":",1,&ctx);
+ md5next((uint8_t *)nonce,strlen(nonce),&ctx);
+ md5next((uint8_t *)":",1,&ctx);
+ if(method==TYPE_RFC2617)
+ {
+ md5next((uint8_t *)NC,strlen(NC),&ctx);
+ md5next((uint8_t *)":",1,&ctx);
+ md5next((uint8_t *)cnonce,strlen(cnonce),&ctx);
+ md5next((uint8_t *)":",1,&ctx);
+ md5next((uint8_t *)qop,strlen(qop),&ctx);
+ md5next((uint8_t *)":",1,&ctx);
+ }
+ md5next((uint8_t *)response,strlen(response),&ctx);
+ md5end(md5,&ctx);
+ bin2hex(md5,MD5_SIZE,response);
+
+ len=strlen(user)+strlen(realm)+strlen(nonce)
+ +strlen(URI)+strlen(cnonce)+strlen(NC)
+ +strlen(response)+strlen(qop)+
+ (method==TYPE_RFC2617?8:7);
+ ptr=bfr;
+ put_header(ptr,len,method);
+ put_element(ptr,user);
+ put_element(ptr,realm);
+ put_element(ptr,nonce);
+ put_element(ptr,URI);
+ put_element(ptr,cnonce);
+ put_element(ptr,NC);
+ put_element(ptr,response);
+ put_element(ptr,qop);
+ break;
+
+ default:goto out;
+ }
+
+ if(io(parm,bfr,len+9,WRITE))goto out;
+
+ if(mode)
+ {
+ if(io(parm,bfr,9,READ))goto out;
+ get_header(bfr,len,method,status);
+ if(len>sizeof(bfr))goto out;
+ if(io(parm,bfr,len,READ))goto out;
+
+ if(status==AUTH_SUCCESS)r=0;
+ else r=-2;
+ }
+ else r=0;
+
+out: memset(bfr,0,sizeof(bfr));
+
+ return r;
+}