rsc | 2277c5d | 2004-03-21 04:33:13 +0000 | [diff] [blame] | 1 | /* |
| 2 | * SSH RSA authentication. |
| 3 | * |
| 4 | * Client protocol: |
| 5 | * read public key |
| 6 | * if you don't like it, read another, repeat |
| 7 | * write challenge |
| 8 | * read response |
| 9 | * all numbers are hexadecimal biginits parsable with strtomp. |
| 10 | */ |
| 11 | |
| 12 | #include "dat.h" |
| 13 | |
| 14 | enum { |
| 15 | CHavePub, |
| 16 | CHaveResp, |
| 17 | |
| 18 | Maxphase, |
| 19 | }; |
| 20 | |
| 21 | static char *phasenames[] = { |
| 22 | [CHavePub] "CHavePub", |
| 23 | [CHaveResp] "CHaveResp", |
| 24 | }; |
| 25 | |
| 26 | struct State |
| 27 | { |
| 28 | RSApriv *priv; |
| 29 | mpint *resp; |
| 30 | int off; |
| 31 | Key *key; |
| 32 | }; |
| 33 | |
| 34 | static RSApriv* |
| 35 | readrsapriv(Key *k) |
| 36 | { |
| 37 | char *a; |
| 38 | RSApriv *priv; |
| 39 | |
| 40 | priv = rsaprivalloc(); |
| 41 | |
| 42 | if((a=strfindattr(k->attr, "ek"))==nil || (priv->pub.ek=strtomp(a, nil, 16, nil))==nil) |
| 43 | goto Error; |
| 44 | if((a=strfindattr(k->attr, "n"))==nil || (priv->pub.n=strtomp(a, nil, 16, nil))==nil) |
| 45 | goto Error; |
| 46 | if((a=strfindattr(k->privattr, "!p"))==nil || (priv->p=strtomp(a, nil, 16, nil))==nil) |
| 47 | goto Error; |
| 48 | if((a=strfindattr(k->privattr, "!q"))==nil || (priv->q=strtomp(a, nil, 16, nil))==nil) |
| 49 | goto Error; |
| 50 | if((a=strfindattr(k->privattr, "!kp"))==nil || (priv->kp=strtomp(a, nil, 16, nil))==nil) |
| 51 | goto Error; |
| 52 | if((a=strfindattr(k->privattr, "!kq"))==nil || (priv->kq=strtomp(a, nil, 16, nil))==nil) |
| 53 | goto Error; |
| 54 | if((a=strfindattr(k->privattr, "!c2"))==nil || (priv->c2=strtomp(a, nil, 16, nil))==nil) |
| 55 | goto Error; |
| 56 | if((a=strfindattr(k->privattr, "!dk"))==nil || (priv->dk=strtomp(a, nil, 16, nil))==nil) |
| 57 | goto Error; |
| 58 | return priv; |
| 59 | |
| 60 | Error: |
| 61 | rsaprivfree(priv); |
| 62 | return nil; |
| 63 | } |
| 64 | |
| 65 | static int |
| 66 | sshrsainit(Proto*, Fsstate *fss) |
| 67 | { |
| 68 | int iscli; |
| 69 | State *s; |
| 70 | |
| 71 | if((iscli = isclient(strfindattr(fss->attr, "role"))) < 0) |
| 72 | return failure(fss, nil); |
| 73 | if(iscli==0) |
| 74 | return failure(fss, "sshrsa server unimplemented"); |
| 75 | |
| 76 | s = emalloc(sizeof *s); |
| 77 | fss->phasename = phasenames; |
| 78 | fss->maxphase = Maxphase; |
| 79 | fss->phase = CHavePub; |
| 80 | fss->ps = s; |
| 81 | return RpcOk; |
| 82 | } |
| 83 | |
| 84 | static int |
| 85 | sshrsaread(Fsstate *fss, void *va, uint *n) |
| 86 | { |
| 87 | RSApriv *priv; |
| 88 | State *s; |
| 89 | |
| 90 | s = fss->ps; |
| 91 | switch(fss->phase){ |
| 92 | default: |
| 93 | return phaseerror(fss, "read"); |
| 94 | case CHavePub: |
| 95 | if(s->key){ |
| 96 | closekey(s->key); |
| 97 | s->key = nil; |
| 98 | } |
| 99 | if((s->key = findkey(fss, Kuser, nil, s->off, fss->attr, nil)) == nil) |
| 100 | return failure(fss, nil); |
| 101 | s->off++; |
| 102 | priv = s->key->priv; |
| 103 | *n = snprint(va, *n, "%B", priv->pub.n); |
| 104 | return RpcOk; |
| 105 | case CHaveResp: |
| 106 | *n = snprint(va, *n, "%B", s->resp); |
| 107 | fss->phase = Established; |
| 108 | return RpcOk; |
| 109 | } |
| 110 | } |
| 111 | |
| 112 | static int |
| 113 | sshrsawrite(Fsstate *fss, void *va, uint) |
| 114 | { |
| 115 | mpint *m; |
| 116 | State *s; |
| 117 | |
| 118 | s = fss->ps; |
| 119 | switch(fss->phase){ |
| 120 | default: |
| 121 | return phaseerror(fss, "write"); |
| 122 | case CHavePub: |
| 123 | if(s->key == nil) |
| 124 | return failure(fss, "no current key"); |
| 125 | m = strtomp(va, nil, 16, nil); |
| 126 | m = rsadecrypt(s->key->priv, m, m); |
| 127 | s->resp = m; |
| 128 | fss->phase = CHaveResp; |
| 129 | return RpcOk; |
| 130 | } |
| 131 | } |
| 132 | |
| 133 | static void |
| 134 | sshrsaclose(Fsstate *fss) |
| 135 | { |
| 136 | State *s; |
| 137 | |
| 138 | s = fss->ps; |
| 139 | if(s->key) |
| 140 | closekey(s->key); |
| 141 | if(s->resp) |
| 142 | mpfree(s->resp); |
| 143 | free(s); |
| 144 | } |
| 145 | |
| 146 | static int |
| 147 | sshrsaaddkey(Key *k) |
| 148 | { |
| 149 | fmtinstall('B', mpconv); |
| 150 | |
| 151 | if((k->priv = readrsapriv(k)) == nil){ |
| 152 | werrstr("malformed key data"); |
| 153 | return -1; |
| 154 | } |
| 155 | return replacekey(k); |
| 156 | } |
| 157 | |
| 158 | static void |
| 159 | sshrsaclosekey(Key *k) |
| 160 | { |
| 161 | rsaprivfree(k->priv); |
| 162 | } |
| 163 | |
| 164 | Proto sshrsa = { |
| 165 | .name= "sshrsa", |
| 166 | .init= sshrsainit, |
| 167 | .write= sshrsawrite, |
| 168 | .read= sshrsaread, |
| 169 | .close= sshrsaclose, |
| 170 | .addkey= sshrsaaddkey, |
| 171 | .closekey= sshrsaclosekey, |
| 172 | }; |