diff options
| author | Eric S. Raymond <esr@thyrsus.com> | 1997-09-30 20:43:30 +0000 | 
|---|---|---|
| committer | Eric S. Raymond <esr@thyrsus.com> | 1997-09-30 20:43:30 +0000 | 
| commit | 06e870380328afef42cb857f7e421466df12aeaa (patch) | |
| tree | c2ae5431aff6c9c4208cc275fd7edbb5d44a241c /rpa.c | |
| parent | 13dc548cb89de96c5906f7034cab5b59ae72dbea (diff) | |
| download | fetchmail-06e870380328afef42cb857f7e421466df12aeaa.tar.gz fetchmail-06e870380328afef42cb857f7e421466df12aeaa.tar.bz2 fetchmail-06e870380328afef42cb857f7e421466df12aeaa.zip | |
The code as I received it from Michael Palmer.
svn path=/trunk/; revision=1442
Diffstat (limited to 'rpa.c')
| -rw-r--r-- | rpa.c | 882 | 
1 files changed, 882 insertions, 0 deletions
| @@ -0,0 +1,882 @@ +/*********************************************************************** +  module:       rpa.c +  program:      fetchmail +  programmer:   Michael J. Palmer <106177.1156@compuserve.com> +  date:         29 August 1997 +  compiler:     GCC 2.7.2 +  environment:  RedHat 4.0 Linux 2.0.18 +  description:  RPA authorisation code for POP3 client + ***********************************************************************/ + +#include  <stdio.h> +#include  <unistd.h> +#include  <ctype.h> + +#include  "socket.h" +#include  "fetchmail.h" +#include  "md5.h" + + + +#ifdef TESTMODE +extern unsigned char line1[]; +extern unsigned char line2[]; +extern unsigned char line3[]; + +extern int linecount; +#endif + +#ifndef NO_PROTO +  /* prototypes for internal functions */ +  int  POP3_rpa_resp(unsigned char* argbuf, int socket ); +  void LenAppend(unsigned char** pptr, int len); +  int  LenSkip(unsigned char** pptr, int rxlen); +  int  DecBase64(unsigned char* bufp); +  void EncBase64(unsigned char* bufp, int len); +  void ToUnicode(unsigned char** pptr, unsigned char delim, +                 unsigned char* buf, int* plen, int conv); +  int  SetRealmService(unsigned char* bufp); +  void GenChallenge(unsigned char* buf, int len); +  int  DigestPassphrase(unsigned char* passphrase,unsigned char* rbuf, int unicodeit); +  void CompUserResp(); +  int  CheckUserAuth(); +  void md5(unsigned char* in, int len, unsigned char* out); +#endif + +/* RPA protocol definitions */ + +#define         EARLYVER        "\x01\x00"  /* Earliest supp version */ +#define         LATEVER         "\x03\x00"  /* Latest supp version   */ +#define         HDR             0x60        /* ASN.1 SEQUENCE        */ +#define         MECH            "\x06\x09\x60\x86\x48\x01\x86\xF8\x73\x01\x01" +#define         FLAGS           "\x00\x01"  /* Mutual authentication */ +#define         STRMAX          128         /* Bytes in Unicode      */ +#define         Tsl             14          /* Timestamp bytelen     */ +#define         Pul             16          /* Passphrase digest len */ +#define         Cul             16          /* Usr challenge bytelen */ +#define         Rul             16          /* Usr response bytelen  */ +#define         Aul             16          /* User auth bytelen     */ +#define         Kusl            16          /* Session key bytelen   */ + +#define         UNIPASS         1           /* 1=Unicode 0=iso8859   */ +#define         PS_RPA          42          /* Return code           */ + +/* RPA authentication items */ + +unsigned char   Cs[256];                    /* Service challenge     */ +int             Csl;                        /* Length of "    "      */ +unsigned char   Ts[Tsl+1];                  /* Timestamp incl \0     */ +unsigned char   Nu[STRMAX];                 /* Username in Unicode   */ +int             Nul;                        /* Length of " in bytes  */ +unsigned char   Ns[STRMAX];                 /* Service in Unicode    */ +int             Nsl;                        /* Length of " in bytes  */ +unsigned char   Nr[STRMAX];                 /* Realm in Unicode      */ +int             Nrl;                        /* Length of " in bytes  */ +unsigned char   Pu[Pul];                    /* Passphrase after MD5  */ +unsigned char   Cu[Cul];                    /* User challenge        */ +unsigned char   Ru[Rul];                    /* User response         */ +unsigned char   Au[Aul];                    /* User auth from Deity  */ +unsigned char   Kusu[Kusl];                 /* Obscured Session key  */ +unsigned char   Kus[Kusl];                  /* Session key           */ + +/********************************************************************* +  function:      POP3_auth_rpa +  description:   send the AUTH RPA commands to the server, and +                 get the server's response. Then progress through the +                 RPA challenge/response protocol until we are +                 (hopefully) granted authorisation. +  arguments: +    userid       user's id@realm e.g. myuserid@csi.com +    passphrase   user's passphrase +                 (upper lower or mixed case as the realm has chosen. +                 spec allows various options :-(   ) +    socket       socket to which the server is connected. + +  return value:  zero if success, else non-zero. +  calls:         SockPrintf, POP3_rpa_resp, EncBase64, DecBase64, +                 LenAppend, GenChallenge +  globals:       read outlevel. + *********************************************************************/ + +int POP3_auth_rpa (unsigned char *userid, unsigned char *passphrase, int socket) +{ +    int      ok,rxlen,verh,verl,i,rll; +    unsigned char buf [POPBUFSIZE]; +    unsigned char *bufp; +    int      status,aulin,kuslin; +    char* stdec[4] = { "Success" , +                     "Restricted user (something wrong with account)" , +                     "Invalid userid or passphrase" , +                     "Deity error" }; + +    /* Initiate RPA authorisation */ + +    SockPrintf(socket,"AUTH RPA\r\n"); + +    if (outlevel == O_VERBOSE) +	fprintf(stderr,"> AUTH RPA\n"); + +    /* Create unicode user name in Nu.              */ +    /* Create MD5 digest of user's passphrase in Pu */ + +    bufp = userid; +    ToUnicode(&bufp, '@', Nu, &Nul, 1);  /* User (lowercase) */ +    DigestPassphrase(passphrase, Pu, UNIPASS); + +    /* Get + response from server (RPA ready) */ + +    if ((ok = POP3_rpa_resp(buf,socket)) != 0) +    { +	if (outlevel > O_SILENT && outlevel < O_VERBOSE) +	    fprintf(stderr,"%s\n",buf); + +	return(ok); +    } + +    /* Assemble Token 1 in buf */ + +    bufp    = buf; +    *bufp++ = HDR; +    LenAppend(&bufp,      17); +    memcpy(bufp, MECH,    11); bufp += 11; +    memcpy(bufp, EARLYVER, 2); bufp += 2; +    memcpy(bufp, LATEVER,  2); bufp += 2; +    memcpy(bufp, FLAGS,    2); bufp += 2; + +    /* Send Token 1, receive Token 2 */ + +    EncBase64(buf, bufp-buf); +#ifndef TESTMODE +    SockPrintf(socket,"%s\r\n",buf); +#endif +    if (outlevel == O_VERBOSE) +	fprintf(stderr,"> %s\n",buf); +    if ((ok = POP3_rpa_resp(buf,socket)) != 0) +    { +	if (outlevel > O_SILENT && outlevel < O_VERBOSE) +	    fprintf(stderr,"%s\n",buf); +	return(ok); +    } +    if ((rxlen = DecBase64(buf)) == 0) +    { +	if (outlevel > O_SILENT) +	    fprintf(stderr,"RPA token 2: Base64 decode error\n"); +	return(PS_RPA); +    } +    bufp = buf; +    *(buf+rxlen) = 0;  /* Terminates realm list */ +    if (LenSkip(&bufp,rxlen) == 0) return(PS_RPA); + +    /* Interpret Token 2 */ + +    verh = *(bufp++); verl = *(bufp++); +    if (outlevel == O_VERBOSE) +	fprintf(stderr,"Service chose RPA version %d.%d\n",verh,verl); +    Csl  = *(bufp++); +    memcpy(Cs, bufp, Csl); +    bufp += Csl; +    if (outlevel == O_VERBOSE) +    { +	fprintf(stderr,"Service challenge (l=%d):",Csl); +	for (i=0; i<Csl; i++) fprintf(stderr," %02X",Cs[i]); +	fprintf(stderr,"\n"); +    } +    memcpy(Ts, bufp, Tsl); +    Ts[Tsl] = 0; +    bufp += Tsl; +    if (outlevel == O_VERBOSE) +	fprintf(stderr,"Service timestamp %s\n",Ts); +    rll = *(bufp++) << 8; rll = rll | *(bufp++); +    if ((bufp-buf+rll) != rxlen) +    { +	if (outlevel > O_SILENT) +	    fprintf(stderr,"RPA token 2 length error\n"); +	return(PS_RPA); +    } +    if (outlevel == O_VERBOSE) +	fprintf(stderr,"Realm list: %s\n",bufp); +    if (SetRealmService(bufp) != 0) +    { +	if (outlevel > O_SILENT) +	    fprintf(stderr,"RPA error in service@realm string\n"); +	return(PS_RPA); +    } + +    /* Assemble Token 3 in buf */ + +    bufp      = buf; +    *(bufp++) = HDR; +    LenAppend(&bufp, 11+2+strlen(userid)+1+Cul+1+Rul ); +    memcpy(bufp, MECH, 11); bufp += 11; +  *(bufp++) = 0; +  *(bufp++) = strlen(userid); +  memcpy(bufp,userid,strlen(userid)); bufp += strlen(userid); +  GenChallenge(Cu,Cul); +  *(bufp++) = Cul; +  memcpy(bufp, Cu, Cul);  bufp += Cul; +  CompUserResp(); +  *(bufp++) = Rul; +  memcpy(bufp, Ru, Rul);  bufp += Rul; + +  /* Send Token 3, receive Token 4 */ + +  EncBase64(buf,bufp-buf); +#ifndef TESTMODE +  SockPrintf(socket,"%s\r\n",buf); +#endif +  if (outlevel == O_VERBOSE) +    fprintf(stderr,"> %s\n",buf); +  if ((ok = POP3_rpa_resp(buf,socket)) != 0) +    { +    if (outlevel > O_SILENT && outlevel < O_VERBOSE) +      fprintf(stderr,"%s\n",buf); +    return(ok); +    } +  if ((rxlen = DecBase64(buf)) == 0) +    { +    if (outlevel > O_SILENT) +      fprintf(stderr,"RPA token 4: Base64 decode error\n"); +    return(PS_RPA); +    } +  bufp = buf; +  if (LenSkip(&bufp,rxlen) == 0) return(PS_RPA); + +  /* Interpret Token 4 */ + +  aulin = *(bufp++); +  if (outlevel == O_VERBOSE) +    { +    fprintf(stderr,"User authentication (l=%d):",aulin); +    for (i=0; i<aulin; i++) fprintf(stderr," %02X",bufp[i]); +    fprintf(stderr,"\n"); +    } +  if (aulin == Aul) memcpy(Au, bufp, Aul); +  bufp += aulin; +  kuslin = *(bufp++); +  if (kuslin == Kusl) memcpy(Kusu, bufp, Kusl); /* blinded */ +  bufp += kuslin; +  if (verh == 3) +    { +    status = *(bufp++); +    if (outlevel == O_VERBOSE) +      fprintf(stderr,"RPA status: %02X\n",status); +    } +  else status = 0; +  if ((bufp - buf) != rxlen) +    { +    if (outlevel > O_SILENT) +      fprintf(stderr,"RPA token 4 length error\n"); +    return(PS_RPA); +    } +  if (status != 0) +    { +    if (outlevel > O_SILENT) +      if (status < 4) +        fprintf(stderr,"RPA rejects you: %s\n",stdec[status]); +      else +        fprintf(stderr,"RPA rejects you, reason unknown\n"); +    return(PS_AUTHFAIL); +    } +  if (Aul != aulin) +    { +    fprintf(stderr,"RPA User Authentication length error: %d\n",aulin); +    return(PS_RPA); +    } +  if (Kusl != kuslin) +    { +    fprintf(stderr,"RPA Session key length error: %d\n",kuslin); +    return(PS_RPA); +    } +  if (CheckUserAuth() != 0) +    { +    if (outlevel > O_SILENT) +      fprintf(stderr,"RPA _service_ auth fail. Spoof server?\n"); +    return(PS_AUTHFAIL); +    } +  if (outlevel == O_VERBOSE) +    { +    fprintf(stderr,"Session key established:"); +    for (i=0; i<Kusl; i++) fprintf(stderr," %02X",Kus[i]); +    fprintf(stderr,"\n"); +    } + +  /* Assemble Token 5 in buf and send (not in ver 2 though)  */ +  /* Version 3.0 definitely replies with +OK to this. I have */ +  /* no idea what sort of response previous versions gave.   */ + +  if (verh != 2) +    { +    bufp      = buf; +    *(bufp++) = HDR; +    LenAppend(&bufp, 1 ); +    *(bufp++) = 0x42; +    EncBase64(buf,bufp-buf); +#ifndef TESTMODE +    SockPrintf(socket,"%s\r\n",buf); +#endif +    if (outlevel == O_VERBOSE) +      fprintf(stderr,"> %s\n",buf); +    if ((ok = POP3_rpa_resp(buf,socket)) != 0) +      { +      if (outlevel > O_SILENT && outlevel < O_VERBOSE) +        fprintf(stderr,"%s\n",buf); +      return(ok); +      } +    } + +  if (outlevel > O_SILENT) +    fprintf(stderr,"RPA authorisation complete\n"); + +  return(PS_SUCCESS); +} + + +/********************************************************************* +  function:      POP3_rpa_resp +  description:   get the server's response to an RPA action. +                 Return received base64 string if successful +  arguments: +    argbuf       buffer to receive the string. +    socket       socket to which the server is connected. + +  return value:  zero if okay, else return code. +  calls:         SockGets +  globals:       reads outlevel. + *********************************************************************/ + +int POP3_rpa_resp (argbuf,socket) +unsigned char *argbuf; +int socket; +{ +  int ok; +  char buf [POPBUFSIZE]; +  char *bufp; +  int sockrc; +  fprintf(stderr, "Get response\n"); +#ifndef TESTMODE +  sockrc = SockRead(socket, buf, sizeof(buf)); +#else +  linecount++; +  if (linecount == 1) strcpy(buf,line1); +  if (linecount == 2) strcpy(buf,line2); +  if (linecount == 3) strcpy(buf,line3); +/*  fprintf(stderr,"--> "); fflush(stderr);  */ +/*  scanf("%s",&buf)                         */ +  sockrc = 0; +#endif +  if (sockrc > 0) { +    buf[sockrc] = 0; +    if (outlevel == O_VERBOSE) +      fprintf(stderr,"%s\n",buf); + +    bufp = buf; +    if ((*buf) == '+') +      { +      bufp++; +/*      if (*bufp == ' ') bufp++; */ +      if (argbuf != NULL) +        strcpy(argbuf,bufp); +      ok=0; +      } +    else if (strcmp(buf,"-ERR") == 0) +      ok = PS_ERROR; +    else ok = PS_PROTOCOL; + +  } +  else +    ok = PS_SOCKET; +  fprintf(stderr, "Get response return %d [%s]\n", ok, buf); +  buf[sockrc] = 0; +  return(ok); +} + +/********************************************************************* +  function:      LenAppend +  description:   Store token length encoded as per ASN.1 DER rules +                 buffer pointer stepped on appropriately. +                 Copes with numbers up to 32767 at least. +  arguments: +    buf          pointer to buffer to receive result +    len          length value to encode + +  return value:  none +  calls:         none +  globals:       none + *********************************************************************/ + +void LenAppend(pptr,len) +unsigned char **pptr; +int  len; +{ +  if (len < 0x80) +    { +    **pptr = len; (*pptr)++; +    } +  else if (len < 0x100) +    { +    **pptr = 0x81; (*pptr)++; +    **pptr = len;  (*pptr)++; +    } +  else +    { +    **pptr = 0x82;       (*pptr)++; +    **pptr = len >> 8;   (*pptr)++; +    **pptr = len & 0xFF; (*pptr)++; +    } +} + +/********************************************************************* +  function:      LenSkip +  description:   Check token header, length, and mechanism, and +                 skip past these. +  arguments: +    pptr         pointer to buffer pointer +    rxlen        number of bytes after base64 decode + +  return value:  0 if error, else token length value +  calls:         none +  globals:       reads outlevel. + *********************************************************************/ + +int LenSkip(pptr,rxlen) +unsigned char **pptr; +int rxlen; +{ +  int len; +  unsigned char *save; +  save = *pptr; +  if (**pptr != HDR) +    { +    if (outlevel > O_SILENT) fprintf(stderr,"Hdr not 60\n"); +    return(0); +    } +  (*pptr)++; +  if (((**pptr) & 0x80) == 0 ) +    { +    len = **pptr; (*pptr)++; +    } +  else if ((**pptr) == 0x81) +    { +    len = *(*pptr+1); (*pptr) += 2; +    } +  else if ((**pptr) == 0x82) +    { +    len = ((*(*pptr+1)) << 8) | *(*pptr+2); +    (*pptr) += 3; +    } +  else len = 0; +  if (len==0) +    { +    if (outlevel>O_SILENT) +      fprintf(stderr,"Token length error\n"); +    } +  else if (((*pptr-save)+len) != rxlen) +    { +    if (outlevel>O_SILENT) +      fprintf(stderr,"Token Length %d disagrees with rxlen %d\n",len,rxlen); +    len = 0; +    } +  else if (memcmp(*pptr,MECH,11)) +    { +    if (outlevel > O_SILENT) +      fprintf(stderr,"Mechanism field incorrect\n"); +    len = 0; +    } +  else (*pptr) += 11;  /* Skip mechanism field */ +  return(len); +} + +/********************************************************************* +  function:      DecBase64 +  description:   Decode a Base64 string, overwriting the original. +                 Note that result cannot be longer than input. + +  arguments: +    bufp         buffer + +  return value:  0 if error, else number of bytes in decoded result +  calls:         none +  globals:       reads outlevel. + *********************************************************************/ + +int DecBase64(bufp) +unsigned char *bufp; +{ +  unsigned int   new, bits=0, cnt=0, i, part=0; +  unsigned char  ch; +  unsigned char* outp=bufp; +  unsigned char* inp=bufp; +  while((ch=*(inp++)) != 0) +    { +    if ((ch != '=') && (ch != ' ') && (ch != '\n') && (ch != '\r')) +      { +      if      ((ch>='A') && (ch <= 'Z'))   new = ch - 'A'; +      else if ((ch>='a') && (ch <= 'z'))   new = ch - 'a' + 26; +      else if ((ch>='0') && (ch <= '9'))   new = ch - '0' + 52; +      else if ( ch=='+'                )   new = 62; +      else if ( ch=='/'                )   new = 63; +      else { +	fprintf(stderr, "dec64 error at char %d: %x\n", inp - bufp, ch); +	return(0); +      } +      part=((part & 0x3F)*64) + new; +      bits += 6; +      if (bits >= 8) +        { +        bits -= 8; +        *outp = (part >> bits); +        cnt++; outp++; +        } +      } +    } +  if (outlevel == O_VERBOSE) +    { +    fprintf(stderr,"Inbound binary data:\n"); +    for (i=0; i<cnt; i++) +      { +      fprintf(stderr," %02X",bufp[i]); +      if (((i % 16)==15) || (i==(cnt-1))) +        fprintf(stderr,"\n"); +      } +    } +  return(cnt); +} + +/********************************************************************* +  function:      EncBase64 +  description:   Encode into Base64 string, overwriting the original. +                 Note that result CAN be longer than input, the buffer +                 is assumed to be big enough. Result string is +                 terminated with \0. + +  arguments: +    bufp         buffer +    len          number of bytes in buffer (>0) + +  return value:  none +  calls:         none +  globals:       reads outlevel; + *********************************************************************/ + +void EncBase64(bufp,len) +unsigned char *bufp; +int  len; +{ +  unsigned char* outp; +  unsigned char  c1,c2,c3; +  char x[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +  int  i; + +  if (outlevel == O_VERBOSE) +    { +    fprintf(stderr,"Outbound data:\n"); +    for (i=0; i<len; i++) +      { +      fprintf(stderr," %02X",bufp[i]); +      if (((i % 16)==15) || (i==(len-1))) +        fprintf(stderr,"\n"); +      } +    } +  outp = bufp + (((len-1)/3)*4); +  *(outp+4) = 0; +  /* So we can do the update in place, start at the far end! */ +  for (i=((len-1)/3)*3; i>=0; i-=3) +    { +    c1 = bufp[i]; +    if ((i+1) < len) c2 = bufp[i+1]; else c2=0; +    if ((i+2) < len) c3 = bufp[i+2]; else c3=0; +    *(outp) = x[c1/4]; +    *(outp+1) = x[((c1 & 3)*16) + (c2/16)]; +    if ((i+1) < len) *(outp+2) = x[((c2 & 0x0F)*4) + (c3/64)]; +      else *(outp+2) = '='; +    if ((i+2) < len) *(outp+3) = x[c3 & 0x3F]; +      else *(outp+3) = '='; +    outp -= 4; +    } +} + +/********************************************************************* +  function:      ToUnicode +  description:   Convert ASCII (or iso-8859-1) byte string into +                 Unicode. Ensure length isn't too long (STRMAX). + +  arguments: +    pptr         pointer to input buffer +    delim        delimiter character (in addition to \0) +    buf          buffer where Unicode will go +    plen         pointer to length variable (# bytes output) +    conv         1 to convert to lowercase, 0 leaves alone + +  return value:  none +  calls:         none +  globals:       reads outlevel; + *********************************************************************/ + +void ToUnicode(pptr,delim,buf,plen,conv) +unsigned char **pptr; /* input string  */ +unsigned char delim; +unsigned char *buf;   /* output buffer */ +int  *plen; +int conv; +{ +  unsigned char *p; +  int i; +  *plen = 0; p=buf; +  while ( ((**pptr)!=delim) && ((**pptr)!=0) && ((*plen)<STRMAX) ) +    { +    *(p++) = 0; +    if (conv) +      *(p++) = tolower(**pptr); +    else +      *(p++) = (**pptr); +    (*plen) += 2; +    (*pptr)++; +    } +  if ( ((**pptr)!=delim) && ((**pptr)!=0) && ((*plen)==STRMAX) ) +    { +    if (outlevel > O_SILENT) +      fprintf(stderr,"RPA String too long\n"); +    *plen = 0; +    } +  if (outlevel == O_VERBOSE) +    { +    fprintf(stderr,"Unicode:"); +    for (i=0; i<(*plen); i++) fprintf(stderr,"%02X ",buf[i]); +    fprintf(stderr,"\n"); +    } +} + +/********************************************************************* +  function:      SetRealmService +  description:   Select a realm from list, and store it. + +  arguments: +    bufp         pointer to buffer + +  return value:  none +  calls:         none +  globals:       reads outlevel. +                 writes Ns Nsl Nr Nrl + *********************************************************************/ + +int SetRealmService(bufp) +unsigned char* bufp; +{ +  /* For the moment we pick the first available realm. It would */ +  /* make more sense to verify that the realm which the user    */ +  /* has given (as part of id) is in the list, and select it's  */ +  /* corresponding service name.                                */ +  ToUnicode(&bufp, '@', Ns, &Nsl, 1);  /* Service    */ +  bufp++;                              /* Skip the @ */ +  ToUnicode(&bufp, ' ', Nr, &Nrl, 1);  /* Realm name */ +  if ((Nrl == 0) || (Nsl == 0)) +    return(PS_RPA); +  return(0); +} + +/********************************************************************* +  function:      GenChallenge +  description:   Generate a random User challenge + +  arguments: +    buf          pointer to buffer +    len          length in bytes + +  return value:  none +  calls:         none +  globals:       reads outlevel. +                 reads /dev/random + *********************************************************************/ + +void GenChallenge(buf,len) +unsigned char *buf; +int  len; +{ +  int  i; +  FILE *devrandom; +  devrandom = fopen("/dev/urandom","rb"); +  if (devrandom == NULL) +    { +    if (outlevel > O_SILENT) +      fprintf(stderr,"RPA Failed open of /dev/random. This shouldn't\n"); +      fprintf(stderr,"    prevent you logging in, but means you\n"); +      fprintf(stderr,"    cannot be sure you are talking to the\n"); +      fprintf(stderr,"    service that you think you are (replay\n"); +      fprintf(stderr,"    attacks by a dishonest service are possible.)\n"); +    } +  for (i=0; i<len; i++) buf[i] = fgetc(devrandom); +//  for (i=0; i<len; i++) buf[i] = random(); +  fclose(devrandom); +  if (outlevel == O_VERBOSE) +    { +    fprintf(stderr,"User challenge:"); +    for (i=0; i<len; i++) fprintf(stderr," %02X",buf[i]); +    fprintf(stderr,"\n"); +    } +} + +/********************************************************************* +  function:      DigestPassphrase +  description:   Use MD5 to compute digest (Pu) of Passphrase +                 Don't map to lower case. We assume the user is +                 aware of the case requirement of the realm. +                 (Why oh why have options in the spec?!) +  arguments: +    passphrase   buffer containing string, \0 terminated +    rbuf         buffer into which digest goes + +  return value:  0 if ok, else error code +  calls:         md5 +  globals:       reads authentication items listed above. +                 writes Pu. + *********************************************************************/ + +int DigestPassphrase(passphrase,rbuf,unicodeit) +unsigned char *passphrase; +unsigned char *rbuf; +int unicodeit; +{ +  int   len; +  unsigned char  workarea[STRMAX]; +  unsigned char* ptr; + +  if (unicodeit)  /* Option in spec. Yuck. */ +    { +    ptr = passphrase; +    ToUnicode(&ptr, '\0', workarea, &len, 0); /* No case conv here */ +    if (len == 0) +      return(PS_SYNTAX); +    ptr = workarea; +    } +  else +    { +    ptr = rbuf; +    len = strlen(passphrase); +    } +  md5(ptr,len,rbuf); +  return(0); +} + +/********************************************************************* +  function:      CompUserResp +  description:   Use MD5 to compute User Response (Ru) from +                 Pu Z(48) Nu Ns Nr Cu Cs Ts Pu + +  arguments:     none + +  return value:  none +  calls:         MD5 +  globals:       reads authentication items listed above. +                 writes Ru. + *********************************************************************/ + +void CompUserResp() +{ +  unsigned char  workarea[Pul+48+STRMAX*5+Tsl+Pul]; +  unsigned char* p; +  p = workarea; +  memcpy(p , Pu,  Pul); p += Pul; +  memset(p , '\0', 48); p += 48; +  memcpy(p , Nu,  Nul); p += Nul; +  memcpy(p , Ns,  Nsl); p += Nsl; +  memcpy(p , Nr,  Nrl); p += Nrl; +  memcpy(p , Cu,  Cul); p += Cul; +  memcpy(p , Cs,  Csl); p += Csl; +  memcpy(p , Ts,  Tsl); p += Tsl; +  memcpy(p , Pu,  Pul); p += Pul; +  md5(workarea,p-workarea,Ru); +} + +/********************************************************************* +  function:      CheckUserAuth +  description:   Use MD5 to verify Authentication Response to User (Au) +                 using  Pu Z(48) Ns Nu Nr Kusu Cs Cu Ts Kus Pu +                 Also creates unobscured session key Kus from obscured +                 one Kusu + +  arguments:     none + +  return value:  0 if ok, PS_RPA if mismatch +  calls:         MD5 +  globals:       reads authentication items listed above. +                 writes Ru. + *********************************************************************/ + +int CheckUserAuth() +{ +  unsigned char  workarea[Pul+48+STRMAX*7+Tsl+Pul]; +  unsigned char* p; +  unsigned char  md5ans[16]; +  int i; +    /* Create unobscured Kusu */ +  p = workarea; +  memcpy(p , Pu,  Pul); p += Pul; +  memset(p , '\0', 48); p += 48; +  memcpy(p , Ns,  Nsl); p += Nsl; +  memcpy(p , Nu,  Nul); p += Nul; +  memcpy(p , Nr,  Nrl); p += Nrl; +  memcpy(p , Cs,  Csl); p += Csl; +  memcpy(p , Cu,  Cul); p += Cul; +  memcpy(p , Ts,  Tsl); p += Tsl; +  memcpy(p , Pu,  Pul); p += Pul; +  md5(workarea,p-workarea,md5ans); +  for (i=0; i<16; i++) Kus[i] = Kusu[i] ^ md5ans[i]; +    /* Compute Au from our information */ +  p = workarea; +  memcpy(p , Pu,  Pul); p += Pul; +  memset(p , '\0', 48); p += 48; +  memcpy(p , Ns,  Nsl); p += Nsl; +  memcpy(p , Nu,  Nul); p += Nul; +  memcpy(p , Nr,  Nrl); p += Nrl; +  memcpy(p , Kusu,Kusl);p += Kusl; +  memcpy(p , Cs,  Csl); p += Csl; +  memcpy(p , Cu,  Cul); p += Cul; +  memcpy(p , Ts,  Tsl); p += Tsl; +  memcpy(p , Kus, Kusl);p += Kusl; +  memcpy(p , Pu,  Pul); p += Pul; +  md5(workarea,p-workarea,md5ans); +    /* Compare the two */ +  for (i=0; i<16; i++) +    if (Au[i] != md5ans[i]) return(PS_RPA); +  return(0); +} + +/********************************************************************* +  function:      md5 +  description:   Apply MD5 +  arguments: +    in           input byte stream +    len          length in bytes +    out          128 bit result buffer +  return value:  none +  calls:         MD5 primitives +  globals:       reads outlevel + *********************************************************************/ + +void md5(in,len,out) +unsigned char*    in; +int      len; +unsigned char*    out; +{ +  int      i; +  MD5_CTX  md5context; + +  if (outlevel == O_VERBOSE) +    { +    fprintf(stderr,"MD5 being applied to data block:\n"); +    for (i=0; i<len; i++) +      { +      fprintf(stderr," %02X",in[i]); +      if (((i % 16)==15) || (i==(len-1))) fprintf(stderr,"\n"); +      } +    } +  MD5Init(   &md5context ); +  MD5Update( &md5context, in, len ); +  MD5Final(  out, &md5context ); +  if (outlevel == O_VERBOSE) +    { +    fprintf(stderr,"MD5 result is: "); +    for (i=0; i<16; i++) fprintf(stderr,"%02X ",out[i]); +    fprintf(stderr,"\n"); +    } +} | 
