00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifdef __FreeBSD__
00023 #include <sys/types.h>
00024 #endif
00025 #include <stdlib.h>
00026 #include <stdio.h>
00027 #include <string.h>
00028 #include <ctype.h>
00029 #include <openssl/md5.h>
00030 #include "milenage.h"
00031
00032 #define MAX_HEADER_LEN 2049
00033 #define MD5_HASH_SIZE 16
00034 #define HASH_HEX_SIZE 2*MD5_HASH_SIZE
00035
00036
00037
00038
00039 #define KLEN 16
00040 typedef u_char K[KLEN];
00041 #define RANDLEN 16
00042 typedef u_char RAND[RANDLEN];
00043 #define AUTNLEN 16
00044 typedef u_char AUTN[AUTNLEN];
00045
00046 #define AKLEN 6
00047 typedef u_char AK[AKLEN];
00048 #define AMFLEN 2
00049 typedef u_char AMF[AMFLEN];
00050 #define MACLEN 8
00051 typedef u_char MAC[MACLEN];
00052 #define CKLEN 16
00053 typedef u_char CK[CKLEN];
00054 #define IKLEN 16
00055 typedef u_char IK[IKLEN];
00056 #define SQNLEN 6
00057 typedef u_char SQN[SQNLEN];
00058 #define AUTSLEN 14
00059 typedef char AUTS[AUTSLEN];
00060 #define AUTS64LEN 29
00061 typedef char AUTS64[AUTS64LEN];
00062 #define RESLEN 8
00063 typedef unsigned char RES[RESLEN+1];
00064 #define RESHEXLEN 17
00065 typedef char RESHEX[RESHEXLEN];
00066 #define OPLEN 16
00067 typedef u_char OP[OPLEN];
00068
00069 AMF amfstar= { '\0' , '\0'} ;
00070 SQN sqn_he={0x00,0x00,0x00,0x00,0x00,0x00};
00071
00072
00073
00074
00075 int createAuthHeaderMD5(char * user, char * password, char * method,
00076 char * uri, char * msgbody, char * auth,
00077 char * algo, char * result);
00078 int createAuthHeaderAKAv1MD5(char * user, char * OP,
00079 char * AMF,
00080 char * K,
00081 char * method,
00082 char * uri, char * msgbody, char * auth, char *algo,
00083 char * result);
00084
00085
00086
00087
00088 void hashToHex (unsigned char *_b, unsigned char *_h)
00089 {
00090 unsigned short i;
00091 unsigned char j;
00092
00093 for (i = 0; i < MD5_HASH_SIZE; i++) {
00094 j = (_b[i] >> 4) & 0xf;
00095 if (j <= 9) {
00096 _h[i * 2] = (j + '0');
00097 } else {
00098 _h[i * 2] = (j + 'a' - 10);
00099 }
00100 j = _b[i] & 0xf;
00101 if (j <= 9) {
00102 _h[i * 2 + 1] = (j + '0');
00103 } else {
00104 _h[i * 2 + 1] = (j + 'a' - 10);
00105 }
00106 };
00107 _h[HASH_HEX_SIZE] = '\0';
00108 }
00109
00110 char *stristr (const char *s1, const char *s2) {
00111 char *cp = (char*) s1;
00112 char *p1, *p2, *endp;
00113 char l, r;
00114
00115 endp = (char*)s1 + (strlen(s1) - strlen(s2)) ;
00116 while (*cp && (cp <= endp)) {
00117 p1 = cp;
00118 p2 = (char*)s2;
00119 while (*p1 && *p2) {
00120 l = toupper(*p1);
00121 r = toupper(*p2);
00122 if (l != r) {
00123 break;
00124 }
00125 p1++;
00126 p2++;
00127 }
00128 if (*p2 == 0) {
00129 return cp;
00130 }
00131 cp++;
00132 }
00133 return 0;
00134 }
00135
00136 int createAuthHeader(char * user, char * password, char * method,
00137 char * uri, char * msgbody, char * auth,
00138 char * aka_OP,
00139 char * aka_AMF,
00140 char * aka_K,
00141 char * result) {
00142
00143 char algo[32]="MD5";
00144 char *start, *end;
00145
00146 if ((start = stristr(auth, "Digest")) == NULL) {
00147 sprintf(result, "createAuthHeader: authentication must be digest");
00148 return 0;
00149 }
00150
00151 if ((start = stristr(auth, "algorithm=")) != NULL) {
00152 start = start + strlen("algorithm=");
00153 if (*start == '"') { start++; }
00154 end = start + strcspn(start, " ,\"\r\n");
00155 strncpy(algo, start, end - start);
00156 algo[end - start] ='\0';
00157
00158 }
00159
00160 if (strncasecmp(algo, "MD5", 3)==0) {
00161 return createAuthHeaderMD5(user,password,method,uri,msgbody,auth,algo,result);
00162 } else if (strncasecmp(algo, "AKAv1-MD5", 9)==0) {
00163 return createAuthHeaderAKAv1MD5(user, aka_OP,
00164 aka_AMF,
00165 aka_K,
00166 method,uri,msgbody,auth,algo,result);
00167 }else{
00168 sprintf(result, "createAuthHeader: authentication must use MD5 or AKAv1-MD5");
00169 return 0;
00170 }
00171 }
00172
00173
00174 int createAuthHeaderMD5(char * user, char * password, char * method,
00175 char * uri, char * msgbody, char * auth,
00176 char * algo, char * result) {
00177
00178 unsigned char ha1[MD5_HASH_SIZE], ha2[MD5_HASH_SIZE];
00179 unsigned char resp[MD5_HASH_SIZE], body[MD5_HASH_SIZE];
00180 unsigned char ha1_hex[HASH_HEX_SIZE+1], ha2_hex[HASH_HEX_SIZE+1];
00181 unsigned char resp_hex[HASH_HEX_SIZE+1], body_hex[HASH_HEX_SIZE+1];
00182 char tmp[MAX_HEADER_LEN], authtype[16], cnonce[32], nc[32], opaque[64];
00183 char *start, *end;
00184 static unsigned int mync = 1;
00185 int has_opaque = 0;
00186 MD5_CTX Md5Ctx;
00187
00188
00189 cnonce[0] = '\0';
00190 authtype[0] = '\0';
00191 if ((start = stristr(auth, "qop=")) != NULL) {
00192 start = start + strlen("qop=");
00193 if (*start == '"') { start++; }
00194 end = start + strcspn(start, " ,\"\r\n");
00195 strncpy(authtype, start, end - start);
00196 authtype[end - start] ='\0';
00197 sprintf(cnonce, "%x", rand());
00198 sprintf(nc, "%08x", mync);
00199 }
00200
00201
00202 opaque[0] = '\0';
00203 if ((start = stristr(auth, "opaque=")) != NULL) {
00204 start = start + strlen("opaque=");
00205 if (*start == '"') { start++; }
00206 end = start + strcspn(start, " ,\"\r\n");
00207 strncpy(opaque, start, end - start);
00208 opaque[end - start] ='\0';
00209 has_opaque = 1;
00210 }
00211
00212
00213 if ((start = stristr(auth, "realm=")) == NULL) {
00214 sprintf(result, "createAuthHeaderMD5: couldn't parse realm in '%s'", auth);
00215 return 0;
00216 }
00217 start = start + strlen("realm=");
00218 if (*start == '"') { start++; }
00219 end = start + strcspn(start, ",\"\r\n");
00220 strncpy(tmp, start, end - start);
00221 tmp[end - start] ='\0';
00222
00223
00224 MD5_Init(&Md5Ctx);
00225 MD5_Update(&Md5Ctx, user, strlen(user));
00226 MD5_Update(&Md5Ctx, ":", 1);
00227 MD5_Update(&Md5Ctx, tmp, strlen(tmp));
00228 MD5_Update(&Md5Ctx, ":", 1);
00229 MD5_Update(&Md5Ctx, password, strlen(password));
00230 MD5_Final(ha1, &Md5Ctx);
00231 hashToHex(&ha1[0], &ha1_hex[0]);
00232
00233 sprintf(result, "Digest username=\"%s\",realm=\"%s\"",user,tmp);
00234 if (cnonce[0] != '\0') {
00235 sprintf(result, "%s,cnonce=\"%s\",nc=%s,qop=%s",result,cnonce,nc,authtype);
00236 }
00237
00238
00239
00240 sprintf(tmp, "%s", uri);
00241
00242
00243 if (stristr(authtype, "auth-int") != NULL) {
00244 MD5_Init(&Md5Ctx);
00245 MD5_Update(&Md5Ctx, msgbody, strlen(msgbody));
00246 MD5_Final(body, &Md5Ctx);
00247 hashToHex(&body[0], &body_hex[0]);
00248 }
00249
00250
00251 MD5_Init(&Md5Ctx);
00252 MD5_Update(&Md5Ctx, method, strlen(method));
00253 MD5_Update(&Md5Ctx, ":", 1);
00254 MD5_Update(&Md5Ctx, tmp, strlen(tmp));
00255 if (stristr(authtype, "auth-int") != NULL) {
00256 MD5_Update(&Md5Ctx, ":", 1);
00257 MD5_Update(&Md5Ctx, &body_hex, HASH_HEX_SIZE);
00258 }
00259 MD5_Final(ha2, &Md5Ctx);
00260 hashToHex(&ha2[0], &ha2_hex[0]);
00261
00262 sprintf(result, "%s,uri=\"%s\"",result,tmp);
00263
00264
00265 if ((start = stristr(auth, "nonce=")) == NULL) {
00266 sprintf(result, "createAuthHeader: couldn't parse nonce");
00267 return 0;
00268 }
00269 start = start + strlen("nonce=");
00270 if (*start == '"') { start++; }
00271 end = start + strcspn(start, " ,\"\r\n");
00272 strncpy(tmp, start, end - start);
00273 tmp[end - start] ='\0';
00274
00275 MD5_Init(&Md5Ctx);
00276 MD5_Update(&Md5Ctx, &ha1_hex, HASH_HEX_SIZE);
00277 MD5_Update(&Md5Ctx, ":", 1);
00278 MD5_Update(&Md5Ctx, tmp, strlen(tmp));
00279 if (cnonce[0] != '\0') {
00280 MD5_Update(&Md5Ctx, ":", 1);
00281 MD5_Update(&Md5Ctx, nc, strlen(nc));
00282 MD5_Update(&Md5Ctx, ":", 1);
00283 MD5_Update(&Md5Ctx, cnonce, strlen(cnonce));
00284 MD5_Update(&Md5Ctx, ":", 1);
00285 MD5_Update(&Md5Ctx, authtype, strlen(authtype));
00286 }
00287 MD5_Update(&Md5Ctx, ":", 1);
00288 MD5_Update(&Md5Ctx, &ha2_hex, HASH_HEX_SIZE);
00289 MD5_Final(resp, &Md5Ctx);
00290 hashToHex(&resp[0], &resp_hex[0]);
00291
00292 sprintf(result, "%s,nonce=\"%s\",response=\"%s\",algorithm=%s",result,tmp,resp_hex,algo);
00293
00294 if (has_opaque) {
00295 sprintf(result, "%s,opaque=\"%s\"",result,opaque);
00296 }
00297
00298 return 1;
00299 }
00300
00301
00302 static int base64_val(char x)\
00303 {
00304 switch(x){
00305 case '=': return -1;
00306 case 'A': return 0;
00307 case 'B': return 1;
00308 case 'C': return 2;
00309 case 'D': return 3;
00310 case 'E': return 4;
00311 case 'F': return 5;
00312 case 'G': return 6;
00313 case 'H': return 7;
00314 case 'I': return 8;
00315 case 'J': return 9;
00316 case 'K': return 10;
00317 case 'L': return 11;
00318 case 'M': return 12;
00319 case 'N': return 13;
00320 case 'O': return 14;
00321 case 'P': return 15;
00322 case 'Q': return 16;
00323 case 'R': return 17;
00324 case 'S': return 18;
00325 case 'T': return 19;
00326 case 'U': return 20;
00327 case 'V': return 21;
00328 case 'W': return 22;
00329 case 'X': return 23;
00330 case 'Y': return 24;
00331 case 'Z': return 25;
00332 case 'a': return 26;
00333 case 'b': return 27;
00334 case 'c': return 28;
00335 case 'd': return 29;
00336 case 'e': return 30;
00337 case 'f': return 31;
00338 case 'g': return 32;
00339 case 'h': return 33;
00340 case 'i': return 34;
00341 case 'j': return 35;
00342 case 'k': return 36;
00343 case 'l': return 37;
00344 case 'm': return 38;
00345 case 'n': return 39;
00346 case 'o': return 40;
00347 case 'p': return 41;
00348 case 'q': return 42;
00349 case 'r': return 43;
00350 case 's': return 44;
00351 case 't': return 45;
00352 case 'u': return 46;
00353 case 'v': return 47;
00354 case 'w': return 48;
00355 case 'x': return 49;
00356 case 'y': return 50;
00357 case 'z': return 51;
00358 case '0': return 52;
00359 case '1': return 53;
00360 case '2': return 54;
00361 case '3': return 55;
00362 case '4': return 56;
00363 case '5': return 57;
00364 case '6': return 58;
00365 case '7': return 59;
00366 case '8': return 60;
00367 case '9': return 61;
00368 case '+': return 62;
00369 case '/': return 63;
00370 }
00371 return 0;
00372 }
00373
00374 char * base64_decode_string( const char *buf, unsigned int len, int *newlen )
00375 {
00376 unsigned int i ;
00377 int j,x1,x2,x3,x4;
00378 char *out;
00379 out = (char *)malloc( ( len * 3/4 ) + 8 );
00380 for(i=0,j=0;i+3<len;i+=4){
00381 x1=base64_val(buf[i]);
00382 x2=base64_val(buf[i+1]);
00383 x3=base64_val(buf[i+2]);
00384 x4=base64_val(buf[i+3]);
00385 out[j++]=(x1<<2) | ((x2 & 0x30)>>4);
00386 out[j++]=((x2 & 0x0F)<<4) | ((x3 & 0x3C)>>2);
00387 out[j++]=((x3 & 0x03)<<6) | (x4 & 0x3F);
00388 }
00389 if (i<len) {
00390 x1 = base64_val(buf[i]);
00391 if (i+1<len)
00392 x2=base64_val(buf[i+1]);
00393 else
00394 x2=-1;
00395 if (i+2<len)
00396 x3=base64_val(buf[i+2]);
00397 else
00398 x3=-1;
00399 if(i+3<len)
00400 x4=base64_val(buf[i+3]);
00401 else x4=-1;
00402 if (x2!=-1) {
00403 out[j++]=(x1<<2) | ((x2 & 0x30)>>4);
00404 if (x3==-1) {
00405 out[j++]=((x2 & 0x0F)<<4) | ((x3 & 0x3C)>>2);
00406 if (x4==-1) {
00407 out[j++]=((x3 & 0x03)<<6) | (x4 & 0x3F);
00408 }
00409 }
00410 }
00411
00412 }
00413
00414 out[j++] = 0;
00415 *newlen=j;
00416 return out;
00417 }
00418
00419
00420 char base64[64]= {
00421 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q',
00422 'R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h',
00423 'i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y',
00424 'z','0','1','2','3','4','5','6','7','8','9','+','/' } ;
00425
00426 char * base64_encode_string( const char *buf, unsigned int len, int *newlen )
00427 {
00428 int i,k;
00429 int triplets,rest;
00430 char *out,*ptr;
00431
00432 triplets = len/3;
00433 rest = len%3;
00434 out = (char *)malloc( ( triplets * 4 ) + 8 );
00435
00436 ptr = out;
00437 for(i=0;i<triplets*3;i+=3){
00438 k = (((unsigned char) buf[i])&0xFC)>>2;
00439 *ptr=base64[k];ptr++;
00440
00441 k = (((unsigned char) buf[i])&0x03)<<4;
00442 k |=(((unsigned char) buf[i+1])&0xF0)>>4;
00443 *ptr=base64[k];ptr++;
00444
00445 k = (((unsigned char) buf[i+1])&0x0F)<<2;
00446 k |=(((unsigned char) buf[i+2])&0xC0)>>6;
00447 *ptr=base64[k];ptr++;
00448
00449 k = (((unsigned char) buf[i+2])&0x3F);
00450 *ptr=base64[k];ptr++;
00451 }
00452 i=triplets*3;
00453 switch(rest){
00454 case 0:
00455 break;
00456 case 1:
00457 k = (((unsigned char) buf[i])&0xFC)>>2;
00458 *ptr=base64[k];ptr++;
00459
00460 k = (((unsigned char) buf[i])&0x03)<<4;
00461 *ptr=base64[k];ptr++;
00462
00463 *ptr='=';ptr++;
00464
00465 *ptr='=';ptr++;
00466 break;
00467 case 2:
00468 k = (((unsigned char) buf[i])&0xFC)>>2;
00469 *ptr=base64[k];ptr++;
00470
00471 k = (((unsigned char) buf[i])&0x03)<<4;
00472 k |=(((unsigned char) buf[i+1])&0xF0)>>4;
00473 *ptr=base64[k];ptr++;
00474
00475 k = (((unsigned char) buf[i+1])&0x0F)<<2;
00476 *ptr=base64[k];ptr++;
00477
00478 *ptr='=';ptr++;
00479 break;
00480 }
00481
00482 *newlen = ptr-out;
00483 return out;
00484 }
00485
00486
00487
00488
00489 char hexa[16]= { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' } ;
00490
00491 int createAuthHeaderAKAv1MD5(char * user, char * aka_OP,
00492 char * aka_AMF,
00493 char * aka_K,
00494 char * method,
00495 char * uri, char * msgbody, char * auth, char *algo,
00496 char * result) {
00497
00498 char tmp[MAX_HEADER_LEN] ;
00499 char *start, *end;
00500 int has_auts = 0, resuf = 1;
00501 char *nonce64, *nonce;
00502 int noncelen;
00503 RESHEX resp_hex;
00504 AMF amf;
00505 OP op;
00506 RAND rnd;
00507 AUTS auts_bin;
00508 AUTS64 auts_hex;
00509 MAC mac,xmac;
00510 SQN sqn, sqnxoraka, sqn_ms;
00511 K k;
00512 RES res;
00513 CK ck;
00514 IK ik;
00515 AK ak;
00516 int i;
00517
00518
00519 if ((start = stristr(auth, "nonce=")) == NULL) {
00520 sprintf(result, "createAuthHeaderAKAv1MD5: couldn't parse nonce");
00521 return 0;
00522 }
00523 start = start + strlen("nonce=");
00524 if (*start == '"') { start++; }
00525 end = start + strcspn(start, " ,\"\r\n");
00526 strncpy(tmp, start, end - start);
00527 tmp[end - start] ='\0';
00528
00529
00530 resp_hex[0]=0;
00531 nonce64 = tmp;
00532 nonce = base64_decode_string(nonce64,end-start,&noncelen);
00533 if (noncelen<RANDLEN+AUTNLEN) {
00534 sprintf(result,"createAuthHeaderAKAv1MD5 : Nonce is too short %d < %d expected \n",
00535 noncelen,RANDLEN+AUTNLEN);
00536 return 0;
00537 }
00538 memcpy(rnd,nonce,RANDLEN);
00539 memcpy(sqnxoraka,nonce+RANDLEN,SQNLEN);
00540 memcpy(mac,nonce+RANDLEN+SQNLEN+AMFLEN,MACLEN);
00541 memcpy(k,aka_K,KLEN);
00542 memcpy(amf,aka_AMF,AMFLEN);
00543 memcpy(op,aka_OP,OPLEN);
00544
00545
00546 f2345(k,rnd,res,ck,ik,ak,op);
00547 res[RESLEN]='\0';
00548
00549
00550 for (i=0; i < SQNLEN; i++)
00551 sqn[i] = sqnxoraka[i] ^ ak[i];
00552
00553
00554 f1(k,rnd,sqn,(unsigned char*)aka_AMF,xmac,op);
00555 if (memcmp(mac,xmac,MACLEN)!=0) {
00556 sprintf(result,"createAuthHeaderAKAv1MD5 : MAC != eXpectedMAC -> Server might not know the secret (man-in-the-middle attack?) \n");
00557
00558 }
00559
00560
00561
00562
00563
00564 if (1) {
00565 sqn_he[5] = sqn[5];
00566 has_auts = 0;
00567
00568 for(i=0;i<RESLEN;i++){
00569 resp_hex[2*i]=hexa[(res[i]&0xF0)>>4];
00570 resp_hex[2*i+1]=hexa[res[i]&0x0F];
00571 }
00572 resp_hex[RESLEN*2]=0;
00573 resuf = createAuthHeaderMD5(user, resp_hex, method, uri, msgbody, auth, algo, result);
00574 } else {
00575 sqn_ms[5] = sqn_he[5] + 1;
00576 f5star(k, rnd, ak, op);
00577 for(i=0; i<SQNLEN; i++)
00578 auts_bin[i]=sqn_ms[i]^ak[i];
00579 f1star(k, rnd, sqn_ms, amf, (unsigned char*)auts_bin+SQNLEN, op);
00580 has_auts = 1;
00581
00582
00583 resuf=createAuthHeaderMD5(user,"",method,uri,msgbody,auth,algo,result);
00584 }
00585 if (has_auts) {
00586
00587 for(i=0;i<AUTSLEN;i++){
00588 auts_hex[2*i]=hexa[(auts_bin[i]&0xF0)>>4];
00589 auts_hex[2*i+1]=hexa[auts_bin[i]&0x0F];
00590 }
00591 auts_hex[AUTS64LEN-1]=0;
00592
00593 sprintf(result, "%s,auts=\"%s\"",result,auts_hex);
00594 }
00595
00596 return 1;
00597 }
00598