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]))
12 #define PUT_32BIT(cp, value) { \
13 (cp)[0] = (unsigned char)((value) >> 24); \
14 (cp)[1] = (unsigned char)((value) >> 16); \
15 (cp)[2] = (unsigned char)((value) >> 8); \
16 (cp)[3] = (unsigned char)(value); }
18 static void getstring(char **data
, int *datalen
, char **p
, int *length
) {
22 *length
= GET_32BIT(*data
);
23 *datalen
-= 4; *data
+= 4;
24 if (*datalen
< *length
)
27 *data
+= *length
; *datalen
-= *length
;
29 static Bignum
getmp(char **data
, int *datalen
) {
34 getstring(data
, datalen
, &p
, &length
);
38 return NULL
; /* negative mp */
39 b
= newbn((length
+1)/2);
40 for (i
= 0; i
< length
; i
++) {
43 b
[j
/2+1] |= ((unsigned char)p
[i
]) << 8;
45 b
[j
/2+1] |= ((unsigned char)p
[i
]);
50 static Bignum
get160(char **data
, int *datalen
) {
56 *data
+= 20; *datalen
-= 20;
59 while (length
> 0 && !p
[0])
61 b
= newbn((length
+1)/2);
62 for (i
= 0; i
< length
; i
++) {
65 b
[j
/2+1] |= ((unsigned char)p
[i
]) << 8;
67 b
[j
/2+1] |= ((unsigned char)p
[i
]);
72 static Bignum dss_p
, dss_q
, dss_g
, dss_y
;
74 static void dss_setkey(char *data
, int len
) {
77 getstring(&data
, &len
, &p
, &slen
);
78 if (!p
|| memcmp(p
, "ssh-dss", 7)) {
82 dss_p
= getmp(&data
, &len
);
83 dss_q
= getmp(&data
, &len
);
84 dss_g
= getmp(&data
, &len
);
85 dss_y
= getmp(&data
, &len
);
88 static char *dss_fmtkey(void) {
90 int len
, i
, pos
, nibbles
;
91 static const char hex
[] = "0123456789abcdef";
94 len
= 8 + 4 + 1; /* 4 x "0x", punctuation, \0 */
95 len
+= 4 * (dss_p
[0] + dss_q
[0] + dss_g
[0] + dss_y
[0]); /* digits */
100 pos
+= sprintf(p
+pos
, "0x");
101 nibbles
= (3 + ssh1_bignum_bitcount(dss_p
))/4; if (nibbles
<1) nibbles
=1;
102 for (i
=nibbles
; i
-- ;)
103 p
[pos
++] = hex
[(bignum_byte(dss_p
, i
/2) >> (4*(i
%2))) & 0xF];
104 pos
+= sprintf(p
+pos
, ",0x");
105 nibbles
= (3 + ssh1_bignum_bitcount(dss_q
))/4; if (nibbles
<1) nibbles
=1;
106 for (i
=nibbles
; i
-- ;)
107 p
[pos
++] = hex
[(bignum_byte(dss_q
, i
/2) >> (4*(i
%2))) & 0xF];
108 pos
+= sprintf(p
+pos
, ",0x");
109 nibbles
= (3 + ssh1_bignum_bitcount(dss_g
))/4; if (nibbles
<1) nibbles
=1;
110 for (i
=nibbles
; i
-- ;)
111 p
[pos
++] = hex
[(bignum_byte(dss_g
, i
/2) >> (4*(i
%2))) & 0xF];
112 pos
+= sprintf(p
+pos
, ",0x");
113 nibbles
= (3 + ssh1_bignum_bitcount(dss_y
))/4; if (nibbles
<1) nibbles
=1;
114 for (i
=nibbles
; i
-- ;)
115 p
[pos
++] = hex
[(bignum_byte(dss_y
, i
/2) >> (4*(i
%2))) & 0xF];
120 static char *dss_fingerprint(void) {
121 struct MD5Context md5c
;
122 unsigned char digest
[16], lenbuf
[4];
123 char buffer
[16*3+40];
128 MD5Update(&md5c
, "\0\0\0\7ssh-dss", 11);
130 #define ADD_BIGNUM(bignum) \
131 numlen = (ssh1_bignum_bitcount(bignum)+8)/8; \
132 PUT_32BIT(lenbuf, numlen); MD5Update(&md5c, lenbuf, 4); \
133 for (i = numlen; i-- ;) { \
134 unsigned char c = bignum_byte(bignum, i); \
135 MD5Update(&md5c, &c, 1); \
143 MD5Final(digest
, &md5c
);
145 sprintf(buffer
, "%d ", ssh1_bignum_bitcount(dss_p
));
146 for (i
= 0; i
< 16; i
++)
147 sprintf(buffer
+strlen(buffer
), "%s%02x", i?
":":"", digest
[i
]);
148 ret
= malloc(strlen(buffer
)+1);
154 static int dss_verifysig(char *sig
, int siglen
, char *data
, int datalen
) {
158 Bignum qm2
, r
, s
, w
, i1
, i2
, i3
, u1
, u2
, sha
, v
;
165 * Commercial SSH (2.0.13) and OpenSSH disagree over the format
166 * of a DSA signature. OpenSSH is in line with the IETF drafts:
167 * it uses a string "ssh-dss", followed by a 40-byte string
168 * containing two 160-bit integers end-to-end. Commercial SSH
169 * can't be bothered with the header bit, and considers a DSA
170 * signature blob to be _just_ the 40-byte string containing
171 * the two 160-bit integers. We tell them apart by measuring
172 * the length: length 40 means the commercial-SSH bug, anything
173 * else is assumed to be IETF-compliant.
175 if (siglen
!= 40) { /* bug not present; read admin fields */
176 getstring(&sig
, &siglen
, &p
, &slen
);
177 if (!p
|| memcmp(p
, "ssh-dss", 7)) {
180 sig
+= 4, siglen
-= 4; /* skip yet another length field */
182 r
= get160(&sig
, &siglen
);
183 s
= get160(&sig
, &siglen
);
188 * Step 1. w <- s^-1 mod q.
192 decbn(qm2
); decbn(qm2
);
193 /* Now qm2 is q-2, and by Fermat's Little Theorem, s^qm2 == s^-1 (mod q).
194 * This is a silly way to do it; may fix it later. */
195 modpow(s
, qm2
, dss_q
, w
);
198 * Step 2. u1 <- SHA(message) * w mod q.
200 u1
= newbn(dss_q
[0]);
201 SHA_Simple(data
, datalen
, hash
);
202 p
= hash
; slen
= 20; sha
= get160(&p
, &slen
);
203 modmul(sha
, w
, dss_q
, u1
);
206 * Step 3. u2 <- r * w mod q.
208 u2
= newbn(dss_q
[0]);
209 modmul(r
, w
, dss_q
, u2
);
212 * Step 4. v <- (g^u1 * y^u2 mod p) mod q.
214 i1
= newbn(dss_p
[0]);
215 i2
= newbn(dss_p
[0]);
216 i3
= newbn(dss_p
[0]);
218 modpow(dss_g
, u1
, dss_p
, i1
);
219 modpow(dss_y
, u2
, dss_p
, i2
);
220 modmul(i1
, i2
, dss_p
, i3
);
221 modmul(i3
, One
, dss_q
, v
);
224 * Step 5. v should now be equal to r.
228 for (i
= 1; i
<= v
[0] || i
<= r
[0]; i
++) {
229 if ((i
> v
[0] && r
[i
] != 0) ||
230 (i
> r
[0] && v
[i
] != 0) ||
231 (i
<= v
[0] && i
<= r
[0] && r
[i
] != v
[i
]))
248 struct ssh_hostkey ssh_dss
= {