smsg.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. #include "ssh.h"
  2. static void
  3. send_ssh_smsg_public_key(Conn *c)
  4. {
  5. int i;
  6. Msg *m;
  7. m = allocmsg(c, SSH_SMSG_PUBLIC_KEY, 2048);
  8. putbytes(m, c->cookie, COOKIELEN);
  9. putRSApub(m, c->serverkey);
  10. putRSApub(m, c->hostkey);
  11. putlong(m, c->flags);
  12. for(i=0; i<c->nokcipher; i++)
  13. c->ciphermask |= 1<<c->okcipher[i]->id;
  14. putlong(m, c->ciphermask);
  15. for(i=0; i<c->nokauthsrv; i++)
  16. c->authmask |= 1<<c->okauthsrv[i]->id;
  17. putlong(m, c->authmask);
  18. sendmsg(m);
  19. }
  20. static void
  21. recv_ssh_cmsg_session_key(Conn *c)
  22. {
  23. int i, id, n, serverkeylen, hostkeylen;
  24. mpint *a, *b;
  25. uchar *buf;
  26. Msg *m;
  27. RSApriv *ksmall, *kbig;
  28. m = recvmsg(c, SSH_CMSG_SESSION_KEY);
  29. id = getbyte(m);
  30. c->cipher = nil;
  31. for(i=0; i<c->nokcipher; i++)
  32. if(c->okcipher[i]->id == id)
  33. c->cipher = c->okcipher[i];
  34. if(c->cipher == nil)
  35. sysfatal("invalid cipher selected");
  36. if(memcmp(getbytes(m, COOKIELEN), c->cookie, COOKIELEN) != 0)
  37. sysfatal("bad cookie");
  38. serverkeylen = mpsignif(c->serverkey->n);
  39. hostkeylen = mpsignif(c->hostkey->n);
  40. ksmall = kbig = nil;
  41. if(serverkeylen+128 <= hostkeylen){
  42. ksmall = c->serverpriv;
  43. kbig = c->hostpriv;
  44. }else if(hostkeylen+128 <= serverkeylen){
  45. ksmall = c->hostpriv;
  46. kbig = c->serverpriv;
  47. }else
  48. sysfatal("server session and host keys do not differ by at least 128 bits");
  49. b = getmpint(m);
  50. debug(DBG_CRYPTO, "encrypted with kbig is %B\n", b);
  51. a = rsadecrypt(kbig, b, nil);
  52. mpfree(b);
  53. b = a;
  54. a = rsaunpad(b);
  55. mpfree(b);
  56. b = a;
  57. debug(DBG_CRYPTO, "encrypted with ksmall is %B\n", b);
  58. a = rsadecrypt(ksmall, b, nil);
  59. mpfree(b);
  60. b = a;
  61. a = rsaunpad(b);
  62. mpfree(b);
  63. b = a;
  64. debug(DBG_CRYPTO, "munged is %B\n", b);
  65. n = (mpsignif(b)+7)/8;
  66. if(n > SESSKEYLEN)
  67. sysfatal("client sent short session key");
  68. buf = emalloc(SESSKEYLEN);
  69. mptoberjust(b, buf, SESSKEYLEN);
  70. mpfree(b);
  71. for(i=0; i<SESSIDLEN; i++)
  72. buf[i] ^= c->sessid[i];
  73. memmove(c->sesskey, buf, SESSKEYLEN);
  74. debug(DBG_CRYPTO, "unmunged is %.*H\n", SESSKEYLEN, buf);
  75. c->flags = getlong(m);
  76. free(m);
  77. }
  78. static AuthInfo*
  79. responselogin(char *user, char *resp)
  80. {
  81. Chalstate *c;
  82. AuthInfo *ai;
  83. if((c = auth_challenge("proto=p9cr user=%q role=server", user)) == nil){
  84. sshlog("auth_challenge failed for %s", user);
  85. return nil;
  86. }
  87. c->resp = resp;
  88. c->nresp = strlen(resp);
  89. ai = auth_response(c);
  90. auth_freechal(c);
  91. return ai;
  92. }
  93. static AuthInfo*
  94. authusername(Conn *c)
  95. {
  96. char *p;
  97. AuthInfo *ai;
  98. /*
  99. * hack for sam users: 'name numbers' gets tried as securid login.
  100. */
  101. if(p = strchr(c->user, ' ')){
  102. *p++ = '\0';
  103. if((ai=responselogin(c->user, p)) != nil)
  104. return ai;
  105. *--p = ' ';
  106. sshlog("bad response: %s", c->user);
  107. }
  108. return nil;
  109. }
  110. static void
  111. authsrvuser(Conn *c)
  112. {
  113. int i;
  114. char *ns, *user;
  115. AuthInfo *ai;
  116. Msg *m;
  117. m = recvmsg(c, SSH_CMSG_USER);
  118. user = getstring(m);
  119. c->user = emalloc(strlen(user)+1);
  120. strcpy(c->user, user);
  121. free(m);
  122. ai = authusername(c);
  123. while(ai == nil){
  124. sendmsg(allocmsg(c, SSH_SMSG_FAILURE, 0));
  125. m = recvmsg(c, 0);
  126. if(m == nil)
  127. badmsg(m, 0);
  128. for(i=0; i<c->nokauthsrv; i++)
  129. if(c->okauthsrv[i]->firstmsg == m->type){
  130. ai = (*c->okauthsrv[i]->fn)(c, m);
  131. break;
  132. }
  133. if(i==c->nokauthsrv)
  134. badmsg(m, 0);
  135. }
  136. sendmsg(allocmsg(c, SSH_SMSG_SUCCESS, 0));
  137. if(noworld(ai->cuid))
  138. ns = "/lib/namespace.noworld";
  139. else
  140. ns = nil;
  141. if(auth_chuid(ai, ns) < 0){
  142. sshlog("auth_chuid to %s: %r", ai->cuid);
  143. sysfatal("auth_chuid: %r");
  144. }
  145. sshlog("logged in as %s", ai->cuid);
  146. auth_freeAI(ai);
  147. }
  148. void
  149. sshserverhandshake(Conn *c)
  150. {
  151. char buf[128], *p;
  152. int i;
  153. /* send id string */
  154. fprint(c->fd[0], "SSH-1.5-Plan9\n");
  155. /* receive id string */
  156. if(readstrnl(c->fd[0], buf, sizeof buf) < 0)
  157. sysfatal("reading server version: %r");
  158. /* id string is "SSH-m.n-comment". We need m=1, n>=5. */
  159. if(strncmp(buf, "SSH-", 4) != 0
  160. || strtol(buf+4, &p, 10) != 1
  161. || *p != '.'
  162. || strtol(p+1, &p, 10) < 5
  163. || *p != '-')
  164. sysfatal("protocol mismatch; got %s, need SSH-1.x for x>=5", buf);
  165. for(i=0; i<COOKIELEN; i++)
  166. c->cookie[i] = fastrand();
  167. calcsessid(c);
  168. send_ssh_smsg_public_key(c);
  169. recv_ssh_cmsg_session_key(c);
  170. c->cstate = (*c->cipher->init)(c, 1); /* turns on encryption */
  171. sendmsg(allocmsg(c, SSH_SMSG_SUCCESS, 0));
  172. authsrvuser(c);
  173. }