Remove the special hooks in ssh.c for pscp. pscp now uses the standard
[u/mdw/putty] / sshdss.c
CommitLineData
7cca0d81 1#include <stdio.h>
2#include <stdlib.h>
3
e5574168 4#include "ssh.h"
5
7cca0d81 6#define GET_32BIT(cp) \
7 (((unsigned long)(unsigned char)(cp)[0] << 24) | \
8 ((unsigned long)(unsigned char)(cp)[1] << 16) | \
9 ((unsigned long)(unsigned char)(cp)[2] << 8) | \
10 ((unsigned long)(unsigned char)(cp)[3]))
11
12static void getstring(char **data, int *datalen, char **p, int *length) {
13 *p = NULL;
14 if (*datalen < 4)
15 return;
16 *length = GET_32BIT(*data);
17 *datalen -= 4; *data += 4;
18 if (*datalen < *length)
19 return;
20 *p = *data;
21 *data += *length; *datalen -= *length;
22}
23static Bignum getmp(char **data, int *datalen) {
24 char *p;
25 int i, j, length;
26 Bignum b;
27
28 getstring(data, datalen, &p, &length);
29 if (!p)
30 return NULL;
31 if (p[0] & 0x80)
32 return NULL; /* negative mp */
33 b = newbn((length+1)/2);
34 for (i = 0; i < length; i++) {
35 j = length - 1 - i;
36 if (j & 1)
37 b[j/2+1] |= ((unsigned char)p[i]) << 8;
38 else
39 b[j/2+1] |= ((unsigned char)p[i]);
40 }
41 return b;
42}
43
44static Bignum get160(char **data, int *datalen) {
45 char *p;
46 int i, j, length;
47 Bignum b;
48
49 p = *data;
50 *data += 20; *datalen -= 20;
51
52 length = 20;
53 while (length > 0 && !p[0])
54 p++, length--;
55 b = newbn((length+1)/2);
56 for (i = 0; i < length; i++) {
57 j = length - 1 - i;
58 if (j & 1)
59 b[j/2+1] |= ((unsigned char)p[i]) << 8;
60 else
61 b[j/2+1] |= ((unsigned char)p[i]);
62 }
63 return b;
64}
65
66static Bignum dss_p, dss_q, dss_g, dss_y;
67
68static void dss_setkey(char *data, int len) {
69 char *p;
70 int slen;
71 getstring(&data, &len, &p, &slen);
72 if (!p || memcmp(p, "ssh-dss", 7)) {
73 dss_p = NULL;
74 return;
75 }
76 dss_p = getmp(&data, &len);
77 dss_q = getmp(&data, &len);
78 dss_g = getmp(&data, &len);
79 dss_y = getmp(&data, &len);
80}
81
82static char *dss_fmtkey(void) {
83 char *p;
84 int len;
85 int i;
86 if (!dss_p)
87 return NULL;
88 len = 7 + 4 + 1; /* "ssh-dss", punctuation, \0 */
89 len += 4 * (dss_p[0] + dss_q[0] + dss_g[0] + dss_y[0]); /* digits */
90 p = malloc(len);
91 if (!p) return NULL;
92 strcpy(p, "ssh-dss:");
93 for (i = dss_p[0]; i > 0; i--) sprintf(p+strlen(p), "%04X", dss_p[i]);
94 strcat(p, "/");
95 for (i = dss_q[0]; i > 0; i--) sprintf(p+strlen(p), "%04X", dss_q[i]);
96 strcat(p, "/");
97 for (i = dss_g[0]; i > 0; i--) sprintf(p+strlen(p), "%04X", dss_g[i]);
98 strcat(p, "/");
99 for (i = dss_y[0]; i > 0; i--) sprintf(p+strlen(p), "%04X", dss_y[i]);
100 return p;
101}
102
103static int dss_verifysig(char *sig, int siglen, char *data, int datalen) {
104 char *p;
105 int i, slen;
106 char hash[20];
107 Bignum qm2, r, s, w, i1, i2, i3, u1, u2, sha, v;
108 int ret;
109
110 if (!dss_p)
111 return 0;
112
113 getstring(&sig, &siglen, &p, &slen);
114 if (!p || memcmp(p, "ssh-dss", 7)) {
115 return 0;
116 }
117 sig += 4, siglen -= 4; /* skip yet another length field */
118 r = get160(&sig, &siglen);
119 s = get160(&sig, &siglen);
120 if (!r || !s)
121 return 0;
122
123 /*
124 * Step 1. w <- s^-1 mod q.
125 */
126 w = newbn(dss_q[0]);
127 qm2 = copybn(dss_q);
128 decbn(qm2); decbn(qm2);
129 /* Now qm2 is q-2, and by Fermat's Little Theorem, s^qm2 == s^-1 (mod q).
130 * This is a silly way to do it; may fix it later. */
131 modpow(s, qm2, dss_q, w);
132
133 /*
134 * Step 2. u1 <- SHA(message) * w mod q.
135 */
136 u1 = newbn(dss_q[0]);
137 SHA_Simple(data, datalen, hash);
138 p = hash; slen = 20; sha = get160(&p, &slen);
139 modmul(sha, w, dss_q, u1);
140
141 /*
142 * Step 3. u2 <- r * w mod q.
143 */
144 u2 = newbn(dss_q[0]);
145 modmul(r, w, dss_q, u2);
146
147 /*
148 * Step 4. v <- (g^u1 * y^u2 mod p) mod q.
149 */
150 i1 = newbn(dss_p[0]);
151 i2 = newbn(dss_p[0]);
152 i3 = newbn(dss_p[0]);
153 v = newbn(dss_q[0]);
154 modpow(dss_g, u1, dss_p, i1);
155 modpow(dss_y, u2, dss_p, i2);
156 modmul(i1, i2, dss_p, i3);
157 modmul(i3, One, dss_q, v);
158
159 /*
160 * Step 5. v should now be equal to r.
161 */
162
163 ret = 1;
164 for (i = 1; i <= v[0] || i <= r[0]; i++) {
165 if ((i > v[0] && r[i] != 0) ||
166 (i > r[0] && v[i] != 0) ||
167 (i <= v[0] && i <= r[0] && r[i] != v[i]))
168 ret = 0;
169 }
170
171 freebn(w);
172 freebn(qm2);
173 freebn(sha);
174 freebn(i1);
175 freebn(i2);
176 freebn(i3);
177 freebn(v);
178 freebn(r);
179 freebn(s);
180
181 return ret;
182}
183
e5574168 184struct ssh_hostkey ssh_dss = {
7cca0d81 185 dss_setkey,
186 dss_fmtkey,
187 dss_verifysig,
e5574168 188 "ssh-dss"
189};