зеркало из https://github.com/github/putty.git
Clean up ssh_keyalg APIs and implementations.
Quite a few of the function pointers in the ssh_keyalg vtable now take ptrlen arguments in place of separate pointer and length pairs. Meanwhile, the various key types' implementations of those functions now work by initialising a BinarySource with the input ptrlen and using the new decode functions to walk along it. One exception is the openssh_createkey method which reads a private key in the wire format used by OpenSSH's SSH-2 agent protocol, which has to consume a prefix of a larger data stream, and tell the caller how much of that data was the private key. That function now takes an actual BinarySource, and passes that directly to the decode functions, so that on return the caller finds that the BinarySource's read pointer has been advanced exactly past the private key. This let me throw away _several_ reimplementations of mpint-reading functions, one in each of sshrsa, sshdss.c and sshecc.c. Worse still, they didn't all have exactly the SSH-2 semantics, because the thing in sshrsa.c whose name suggested it was an mpint-reading function actually tolerated the wrong number of leading zero bytes, which it had to be able to do to cope with the "ssh-rsa" signature format which contains a thing that isn't quite an SSH-2 mpint. Now that deviation is clearly commented!
This commit is contained in:
Родитель
5be57af173
Коммит
ae3edcdfc0
5
cmdgen.c
5
cmdgen.c
|
@ -857,9 +857,8 @@ int main(int argc, char **argv)
|
|||
&origcomment, &error)) {
|
||||
ssh2algf = find_pubkey_alg(ssh2alg);
|
||||
if (ssh2algf)
|
||||
bits = ssh2algf->pubkey_bits(ssh2algf,
|
||||
ssh2blob->s,
|
||||
ssh2blob->len);
|
||||
bits = ssh2algf->pubkey_bits(
|
||||
ssh2algf, make_ptrlen(ssh2blob->s, ssh2blob->len));
|
||||
else
|
||||
bits = -1;
|
||||
} else {
|
||||
|
|
18
import.c
18
import.c
|
@ -670,8 +670,8 @@ struct ssh2_userkey *openssh_pem_read(const Filename *filename,
|
|||
put_mp_ssh2_from_string(blob, privkey.data.ptr, privkey.data.len);
|
||||
|
||||
retkey->data = retkey->alg->createkey(
|
||||
retkey->alg, blob->u, publen,
|
||||
blob->u + publen, blob->len - publen);
|
||||
retkey->alg, make_ptrlen(blob->u, publen),
|
||||
make_ptrlen(blob->u + publen, blob->len - publen));
|
||||
|
||||
if (!retkey->data) {
|
||||
sfree(retkey);
|
||||
|
@ -742,7 +742,8 @@ struct ssh2_userkey *openssh_pem_read(const Filename *filename,
|
|||
retkey = snew(struct ssh2_userkey);
|
||||
retkey->alg = (key->keytype == OP_RSA ? &ssh_rsa : &ssh_dss);
|
||||
retkey->data = retkey->alg->createkey(
|
||||
retkey->alg, blob->u, privptr, blob->u+privptr, blob->len-privptr);
|
||||
retkey->alg, make_ptrlen(blob->u, privptr),
|
||||
make_ptrlen(blob->u+privptr, blob->len-privptr));
|
||||
|
||||
if (!retkey->data) {
|
||||
sfree(retkey);
|
||||
|
@ -1466,13 +1467,13 @@ struct ssh2_userkey *openssh_new_read(const Filename *filename,
|
|||
thiskey.len = (const char *)get_ptr(src) - (const char *)thiskey.ptr;
|
||||
|
||||
if (key_index == key->key_wanted) {
|
||||
const unsigned char *blobptr = thiskey.ptr;
|
||||
int bloblen = thiskey.len;
|
||||
BinarySource src[1];
|
||||
BinarySource_BARE_INIT(src, thiskey.ptr, thiskey.len);
|
||||
|
||||
retkey = snew(struct ssh2_userkey);
|
||||
retkey->comment = NULL;
|
||||
retkey->alg = alg;
|
||||
retkey->data = alg->openssh_createkey(alg, &blobptr, &bloblen);
|
||||
retkey->data = alg->openssh_createkey(alg, src);
|
||||
if (!retkey->data) {
|
||||
errmsg = "unable to create key data structure";
|
||||
goto error;
|
||||
|
@ -2173,8 +2174,9 @@ struct ssh2_userkey *sshcom_read(const Filename *filename, char *passphrase,
|
|||
|
||||
retkey = snew(struct ssh2_userkey);
|
||||
retkey->alg = alg;
|
||||
retkey->data = alg->createkey(alg, blob->u, publen,
|
||||
blob->u + publen, blob->len - publen);
|
||||
retkey->data = alg->createkey(
|
||||
alg, make_ptrlen(blob->u, publen),
|
||||
make_ptrlen(blob->u + publen, blob->len - publen));
|
||||
if (!retkey->data) {
|
||||
sfree(retkey);
|
||||
errmsg = "unable to create key data structure";
|
||||
|
|
|
@ -430,14 +430,7 @@ void pageant_handle_msg(BinarySink *bs,
|
|||
goto add2_cleanup;
|
||||
}
|
||||
|
||||
{
|
||||
const unsigned char *p = get_ptr(msg);
|
||||
int len = get_avail(msg);
|
||||
key->data = key->alg->openssh_createkey(key->alg, &p, &len);
|
||||
assert(len >= 0);
|
||||
assert(len < get_avail(msg));
|
||||
msg->pos += get_avail(msg) - len;
|
||||
}
|
||||
key->data = key->alg->openssh_createkey(key->alg, msg);
|
||||
|
||||
if (!key->data) {
|
||||
pageant_failure_msg(bs, "key setup failed", logctx, logfn);
|
||||
|
|
18
ssh.c
18
ssh.c
|
@ -7192,8 +7192,7 @@ static void do_ssh2_transport(void *vctx)
|
|||
}
|
||||
set_busy_status(ssh->frontend, BUSY_CPU); /* cogitate */
|
||||
s->hostkeydata = get_string(pktin);
|
||||
s->hkey = ssh->hostkey->newkey(ssh->hostkey,
|
||||
s->hostkeydata.ptr, s->hostkeydata.len);
|
||||
s->hkey = ssh->hostkey->newkey(ssh->hostkey, s->hostkeydata);
|
||||
s->f = get_mp_ssh2(pktin);
|
||||
s->sigdata = get_string(pktin);
|
||||
if (get_err(pktin)) {
|
||||
|
@ -7264,8 +7263,7 @@ static void do_ssh2_transport(void *vctx)
|
|||
|
||||
s->hostkeydata = get_string(pktin);
|
||||
put_stringpl(ssh->exhash_bs, s->hostkeydata);
|
||||
s->hkey = ssh->hostkey->newkey(ssh->hostkey,
|
||||
s->hostkeydata.ptr, s->hostkeydata.len);
|
||||
s->hkey = ssh->hostkey->newkey(ssh->hostkey, s->hostkeydata);
|
||||
|
||||
{
|
||||
strbuf *pubpoint = strbuf_new();
|
||||
|
@ -7469,8 +7467,7 @@ static void do_ssh2_transport(void *vctx)
|
|||
s->hostkeydata = get_string(pktin);
|
||||
if (ssh->hostkey) {
|
||||
s->hkey = ssh->hostkey->newkey(ssh->hostkey,
|
||||
s->hostkeydata.ptr,
|
||||
s->hostkeydata.len);
|
||||
s->hostkeydata);
|
||||
put_string(ssh->exhash_bs,
|
||||
s->hostkeydata.ptr, s->hostkeydata.len);
|
||||
}
|
||||
|
@ -7564,8 +7561,7 @@ static void do_ssh2_transport(void *vctx)
|
|||
|
||||
s->hostkeydata = get_string(pktin);
|
||||
put_stringpl(ssh->exhash_bs, s->hostkeydata);
|
||||
s->hkey = ssh->hostkey->newkey(ssh->hostkey,
|
||||
s->hostkeydata.ptr, s->hostkeydata.len);
|
||||
s->hkey = ssh->hostkey->newkey(ssh->hostkey, s->hostkeydata);
|
||||
|
||||
rsakeydata = get_string(pktin);
|
||||
|
||||
|
@ -7704,9 +7700,9 @@ static void do_ssh2_transport(void *vctx)
|
|||
crStopV;
|
||||
}
|
||||
|
||||
if (!ssh->hostkey->verifysig(s->hkey, s->sigdata.ptr, s->sigdata.len,
|
||||
s->exchange_hash,
|
||||
ssh->kex->hash->hlen)) {
|
||||
if (!ssh->hostkey->verifysig(
|
||||
s->hkey, s->sigdata,
|
||||
make_ptrlen(s->exchange_hash, ssh->kex->hash->hlen))) {
|
||||
#ifndef FUZZING
|
||||
bombout(("Server's host key did not match the signature "
|
||||
"supplied"));
|
||||
|
|
16
ssh.h
16
ssh.h
|
@ -394,17 +394,13 @@ struct ssh_kexes {
|
|||
};
|
||||
|
||||
struct ssh_keyalg {
|
||||
ssh_key *(*newkey) (const ssh_keyalg *self,
|
||||
const void *data, int len);
|
||||
ssh_key *(*newkey) (const ssh_keyalg *self, ptrlen data);
|
||||
void (*freekey) (ssh_key *key);
|
||||
char *(*fmtkey) (ssh_key *key);
|
||||
void (*public_blob)(ssh_key *key, BinarySink *);
|
||||
void (*private_blob)(ssh_key *key, BinarySink *);
|
||||
ssh_key *(*createkey) (const ssh_keyalg *self,
|
||||
const void *pub_blob, int pub_len,
|
||||
const void *priv_blob, int priv_len);
|
||||
ssh_key *(*openssh_createkey) (const ssh_keyalg *self,
|
||||
const unsigned char **blob, int *len);
|
||||
ssh_key *(*createkey) (const ssh_keyalg *self, ptrlen pub, ptrlen priv);
|
||||
ssh_key *(*openssh_createkey) (const ssh_keyalg *self, BinarySource *);
|
||||
void (*openssh_fmtkey) (ssh_key *key, BinarySink *);
|
||||
/* OpenSSH private key blobs, as created by openssh_fmtkey and
|
||||
* consumed by openssh_createkey, always (at least so far...) take
|
||||
|
@ -415,10 +411,8 @@ struct ssh_keyalg {
|
|||
* skip over the right number to find the next key in the file.
|
||||
* openssh_private_npieces gives that information. */
|
||||
int openssh_private_npieces;
|
||||
int (*pubkey_bits) (const ssh_keyalg *self,
|
||||
const void *blob, int len);
|
||||
int (*verifysig) (ssh_key *key, const void *sig, int siglen,
|
||||
const void *data, int datalen);
|
||||
int (*pubkey_bits) (const ssh_keyalg *self, ptrlen blob);
|
||||
int (*verifysig) (ssh_key *key, ptrlen sig, ptrlen data);
|
||||
void (*sign) (ssh_key *key, const void *data, int datalen, BinarySink *);
|
||||
const char *name;
|
||||
const char *keytype; /* for host key cache */
|
||||
|
|
171
sshdss.c
171
sshdss.c
|
@ -9,86 +9,25 @@
|
|||
#include "ssh.h"
|
||||
#include "misc.h"
|
||||
|
||||
static void getstring(const char **data, int *datalen,
|
||||
const char **p, int *length)
|
||||
{
|
||||
*p = NULL;
|
||||
if (*datalen < 4)
|
||||
return;
|
||||
*length = toint(GET_32BIT(*data));
|
||||
if (*length < 0)
|
||||
return;
|
||||
*datalen -= 4;
|
||||
*data += 4;
|
||||
if (*datalen < *length)
|
||||
return;
|
||||
*p = *data;
|
||||
*data += *length;
|
||||
*datalen -= *length;
|
||||
}
|
||||
static Bignum getmp(const char **data, int *datalen)
|
||||
{
|
||||
const char *p;
|
||||
int length;
|
||||
Bignum b;
|
||||
|
||||
getstring(data, datalen, &p, &length);
|
||||
if (!p)
|
||||
return NULL;
|
||||
if (p[0] & 0x80)
|
||||
return NULL; /* negative mp */
|
||||
b = bignum_from_bytes(p, length);
|
||||
return b;
|
||||
}
|
||||
|
||||
static Bignum get160(const char **data, int *datalen)
|
||||
{
|
||||
Bignum b;
|
||||
|
||||
if (*datalen < 20)
|
||||
return NULL;
|
||||
|
||||
b = bignum_from_bytes(*data, 20);
|
||||
*data += 20;
|
||||
*datalen -= 20;
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
static void dss_freekey(ssh_key *key); /* forward reference */
|
||||
|
||||
static ssh_key *dss_newkey(const ssh_keyalg *self,
|
||||
const void *vdata, int len)
|
||||
static ssh_key *dss_newkey(const ssh_keyalg *self, ptrlen data)
|
||||
{
|
||||
const char *data = (const char *)vdata;
|
||||
const char *p;
|
||||
int slen;
|
||||
BinarySource src[1];
|
||||
struct dss_key *dss;
|
||||
|
||||
dss = snew(struct dss_key);
|
||||
getstring(&data, &len, &p, &slen);
|
||||
|
||||
#ifdef DEBUG_DSS
|
||||
{
|
||||
int i;
|
||||
printf("key:");
|
||||
for (i = 0; i < len; i++)
|
||||
printf(" %02x", (unsigned char) (data[i]));
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!p || slen != 7 || memcmp(p, "ssh-dss", 7)) {
|
||||
sfree(dss);
|
||||
BinarySource_BARE_INIT(src, data.ptr, data.len);
|
||||
if (!ptrlen_eq_string(get_string(src), "ssh-dss"))
|
||||
return NULL;
|
||||
}
|
||||
dss->p = getmp(&data, &len);
|
||||
dss->q = getmp(&data, &len);
|
||||
dss->g = getmp(&data, &len);
|
||||
dss->y = getmp(&data, &len);
|
||||
|
||||
dss = snew(struct dss_key);
|
||||
dss->p = get_mp_ssh2(src);
|
||||
dss->q = get_mp_ssh2(src);
|
||||
dss->g = get_mp_ssh2(src);
|
||||
dss->y = get_mp_ssh2(src);
|
||||
dss->x = NULL;
|
||||
|
||||
if (!dss->p || !dss->q || !dss->g || !dss->y ||
|
||||
if (get_err(src) ||
|
||||
!bignum_cmp(dss->q, Zero) || !bignum_cmp(dss->p, Zero)) {
|
||||
/* Invalid key. */
|
||||
dss_freekey(&dss->sshk);
|
||||
|
@ -164,29 +103,19 @@ static char *dss_fmtkey(ssh_key *key)
|
|||
return p;
|
||||
}
|
||||
|
||||
static int dss_verifysig(ssh_key *key, const void *vsig, int siglen,
|
||||
const void *data, int datalen)
|
||||
static int dss_verifysig(ssh_key *key, ptrlen sig, ptrlen data)
|
||||
{
|
||||
struct dss_key *dss = FROMFIELD(key, struct dss_key, sshk);
|
||||
const char *sig = (const char *)vsig;
|
||||
const char *p;
|
||||
int slen;
|
||||
char hash[20];
|
||||
BinarySource src[1];
|
||||
unsigned char hash[20];
|
||||
Bignum r, s, w, gu1p, yu2p, gu1yu2p, u1, u2, sha, v;
|
||||
int ret;
|
||||
|
||||
if (!dss->p)
|
||||
return 0;
|
||||
|
||||
#ifdef DEBUG_DSS
|
||||
{
|
||||
int i;
|
||||
printf("sig:");
|
||||
for (i = 0; i < siglen; i++)
|
||||
printf(" %02x", (unsigned char) (sig[i]));
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
BinarySource_BARE_INIT(src, sig.ptr, sig.len);
|
||||
|
||||
/*
|
||||
* Commercial SSH (2.0.13) and OpenSSH disagree over the format
|
||||
* of a DSA signature. OpenSSH is in line with RFC 4253:
|
||||
|
@ -198,15 +127,18 @@ static int dss_verifysig(ssh_key *key, const void *vsig, int siglen,
|
|||
* the length: length 40 means the commercial-SSH bug, anything
|
||||
* else is assumed to be RFC-compliant.
|
||||
*/
|
||||
if (siglen != 40) { /* bug not present; read admin fields */
|
||||
getstring(&sig, &siglen, &p, &slen);
|
||||
if (!p || slen != 7 || memcmp(p, "ssh-dss", 7)) {
|
||||
return 0;
|
||||
}
|
||||
sig += 4, siglen -= 4; /* skip yet another length field */
|
||||
if (sig.len != 40) { /* bug not present; read admin fields */
|
||||
ptrlen type = get_string(src);
|
||||
sig = get_string(src);
|
||||
|
||||
if (get_err(src) || !ptrlen_eq_string(type, "ssh-dss") ||
|
||||
sig.len != 40)
|
||||
return 0;
|
||||
}
|
||||
r = get160(&sig, &siglen);
|
||||
s = get160(&sig, &siglen);
|
||||
|
||||
/* Now we're sitting on a 40-byte string for sure. */
|
||||
r = bignum_from_bytes(sig.ptr, 20);
|
||||
s = bignum_from_bytes((const char *)sig.ptr + 20, 20);
|
||||
if (!r || !s) {
|
||||
if (r)
|
||||
freebn(r);
|
||||
|
@ -234,10 +166,8 @@ static int dss_verifysig(ssh_key *key, const void *vsig, int siglen,
|
|||
/*
|
||||
* Step 2. u1 <- SHA(message) * w mod q.
|
||||
*/
|
||||
SHA_Simple(data, datalen, (unsigned char *)hash);
|
||||
p = hash;
|
||||
slen = 20;
|
||||
sha = get160(&p, &slen);
|
||||
SHA_Simple(data.ptr, data.len, hash);
|
||||
sha = bignum_from_bytes(hash, 20);
|
||||
u1 = modmul(sha, w, dss->q);
|
||||
|
||||
/*
|
||||
|
@ -291,26 +221,24 @@ static void dss_private_blob(ssh_key *key, BinarySink *bs)
|
|||
put_mp_ssh2(bs, dss->x);
|
||||
}
|
||||
|
||||
static ssh_key *dss_createkey(const ssh_keyalg *self,
|
||||
const void *pub_blob, int pub_len,
|
||||
const void *priv_blob, int priv_len)
|
||||
static ssh_key *dss_createkey(const ssh_keyalg *self, ptrlen pub, ptrlen priv)
|
||||
{
|
||||
BinarySource src[1];
|
||||
ssh_key *sshk;
|
||||
struct dss_key *dss;
|
||||
const char *pb = (const char *) priv_blob;
|
||||
const char *hash;
|
||||
int hashlen;
|
||||
ptrlen hash;
|
||||
SHA_State s;
|
||||
unsigned char digest[20];
|
||||
Bignum ytest;
|
||||
|
||||
sshk = dss_newkey(self, pub_blob, pub_len);
|
||||
sshk = dss_newkey(self, pub);
|
||||
if (!sshk)
|
||||
return NULL;
|
||||
|
||||
dss = FROMFIELD(sshk, struct dss_key, sshk);
|
||||
dss->x = getmp(&pb, &priv_len);
|
||||
if (!dss->x) {
|
||||
BinarySource_BARE_INIT(src, priv.ptr, priv.len);
|
||||
dss->x = get_mp_ssh2(src);
|
||||
if (get_err(src)) {
|
||||
dss_freekey(&dss->sshk);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -318,15 +246,14 @@ static ssh_key *dss_createkey(const ssh_keyalg *self,
|
|||
/*
|
||||
* Check the obsolete hash in the old DSS key format.
|
||||
*/
|
||||
hashlen = -1;
|
||||
getstring(&pb, &priv_len, &hash, &hashlen);
|
||||
if (hashlen == 20) {
|
||||
hash = get_string(src);
|
||||
if (hash.len == 20) {
|
||||
SHA_Init(&s);
|
||||
put_mp_ssh2(&s, dss->p);
|
||||
put_mp_ssh2(&s, dss->q);
|
||||
put_mp_ssh2(&s, dss->g);
|
||||
SHA_Final(&s, digest);
|
||||
if (0 != memcmp(hash, digest, 20)) {
|
||||
if (0 != memcmp(hash.ptr, digest, 20)) {
|
||||
dss_freekey(&dss->sshk);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -347,20 +274,19 @@ static ssh_key *dss_createkey(const ssh_keyalg *self,
|
|||
}
|
||||
|
||||
static ssh_key *dss_openssh_createkey(const ssh_keyalg *self,
|
||||
const unsigned char **blob, int *len)
|
||||
BinarySource *src)
|
||||
{
|
||||
const char **b = (const char **) blob;
|
||||
struct dss_key *dss;
|
||||
|
||||
dss = snew(struct dss_key);
|
||||
|
||||
dss->p = getmp(b, len);
|
||||
dss->q = getmp(b, len);
|
||||
dss->g = getmp(b, len);
|
||||
dss->y = getmp(b, len);
|
||||
dss->x = getmp(b, len);
|
||||
dss->p = get_mp_ssh2(src);
|
||||
dss->q = get_mp_ssh2(src);
|
||||
dss->g = get_mp_ssh2(src);
|
||||
dss->y = get_mp_ssh2(src);
|
||||
dss->x = get_mp_ssh2(src);
|
||||
|
||||
if (!dss->p || !dss->q || !dss->g || !dss->y || !dss->x ||
|
||||
if (get_err(src) ||
|
||||
!bignum_cmp(dss->q, Zero) || !bignum_cmp(dss->p, Zero)) {
|
||||
/* Invalid key. */
|
||||
dss_freekey(&dss->sshk);
|
||||
|
@ -381,14 +307,13 @@ static void dss_openssh_fmtkey(ssh_key *key, BinarySink *bs)
|
|||
put_mp_ssh2(bs, dss->x);
|
||||
}
|
||||
|
||||
static int dss_pubkey_bits(const ssh_keyalg *self,
|
||||
const void *blob, int len)
|
||||
static int dss_pubkey_bits(const ssh_keyalg *self, ptrlen pub)
|
||||
{
|
||||
ssh_key *sshk;
|
||||
struct dss_key *dss;
|
||||
int ret;
|
||||
|
||||
sshk = dss_newkey(self, blob, len);
|
||||
sshk = dss_newkey(self, pub);
|
||||
if (!sshk)
|
||||
return -1;
|
||||
|
||||
|
|
189
sshecc.c
189
sshecc.c
|
@ -1590,47 +1590,12 @@ static void _ecdsa_sign(const Bignum privateKey, const struct ec_curve *curve,
|
|||
* Misc functions
|
||||
*/
|
||||
|
||||
static void getstring(const char **data, int *datalen,
|
||||
const char **p, int *length)
|
||||
static Bignum BinarySource_get_mp_le(BinarySource *src)
|
||||
{
|
||||
*p = NULL;
|
||||
if (*datalen < 4)
|
||||
return;
|
||||
*length = toint(GET_32BIT(*data));
|
||||
if (*length < 0)
|
||||
return;
|
||||
*datalen -= 4;
|
||||
*data += 4;
|
||||
if (*datalen < *length)
|
||||
return;
|
||||
*p = *data;
|
||||
*data += *length;
|
||||
*datalen -= *length;
|
||||
}
|
||||
|
||||
static Bignum getmp(const char **data, int *datalen)
|
||||
{
|
||||
const char *p;
|
||||
int length;
|
||||
|
||||
getstring(data, datalen, &p, &length);
|
||||
if (!p)
|
||||
return NULL;
|
||||
if (p[0] & 0x80)
|
||||
return NULL; /* negative mp */
|
||||
return bignum_from_bytes(p, length);
|
||||
}
|
||||
|
||||
static Bignum getmp_le(const char **data, int *datalen)
|
||||
{
|
||||
const char *p;
|
||||
int length;
|
||||
|
||||
getstring(data, datalen, &p, &length);
|
||||
if (!p)
|
||||
return NULL;
|
||||
return bignum_from_bytes_le(p, length);
|
||||
ptrlen mp_str = get_string(src);
|
||||
return bignum_from_bytes_le(mp_str.ptr, mp_str.len);
|
||||
}
|
||||
#define get_mp_le(src) BinarySource_get_mp_le(BinarySource_UPCAST(src))
|
||||
|
||||
static int decodepoint_ed(const char *p, int length, struct ec_point *point)
|
||||
{
|
||||
|
@ -1709,15 +1674,13 @@ static int decodepoint(const char *p, int length, struct ec_point *point)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int getmppoint(const char **data, int *datalen, struct ec_point *point)
|
||||
static int BinarySource_get_point(BinarySource *src, struct ec_point *point)
|
||||
{
|
||||
const char *p;
|
||||
int length;
|
||||
|
||||
getstring(data, datalen, &p, &length);
|
||||
if (!p) return 0;
|
||||
return decodepoint(p, length, point);
|
||||
ptrlen str = get_string(src);
|
||||
if (get_err(src)) return 0;
|
||||
return decodepoint(str.ptr, str.len, point);
|
||||
}
|
||||
#define get_point(src, pt) BinarySource_get_point(BinarySource_UPCAST(src), pt)
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
* Exposed ECDSA interface
|
||||
|
@ -1750,30 +1713,24 @@ static void ecdsa_freekey(ssh_key *key)
|
|||
sfree(ec);
|
||||
}
|
||||
|
||||
static ssh_key *ecdsa_newkey(const ssh_keyalg *self,
|
||||
const void *vdata, int len)
|
||||
static ssh_key *ecdsa_newkey(const ssh_keyalg *self, ptrlen data)
|
||||
{
|
||||
const struct ecsign_extra *extra =
|
||||
(const struct ecsign_extra *)self->extra;
|
||||
const char *data = (const char *)vdata;
|
||||
const char *p;
|
||||
int slen;
|
||||
BinarySource src[1];
|
||||
struct ec_key *ec;
|
||||
struct ec_curve *curve;
|
||||
|
||||
getstring(&data, &len, &p, &slen);
|
||||
BinarySource_BARE_INIT(src, data.ptr, data.len);
|
||||
get_string(src);
|
||||
|
||||
if (!p) {
|
||||
return NULL;
|
||||
}
|
||||
curve = extra->curve();
|
||||
assert(curve->type == EC_WEIERSTRASS || curve->type == EC_EDWARDS);
|
||||
|
||||
/* Curve name is duplicated for Weierstrass form */
|
||||
if (curve->type == EC_WEIERSTRASS) {
|
||||
getstring(&data, &len, &p, &slen);
|
||||
if (!p) return NULL;
|
||||
if (!match_ssh_id(slen, p, curve->name)) return NULL;
|
||||
if (!ptrlen_eq_string(get_string(src), curve->name))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ec = snew(struct ec_key);
|
||||
|
@ -1785,7 +1742,7 @@ static ssh_key *ecdsa_newkey(const ssh_keyalg *self,
|
|||
ec->publicKey.y = NULL;
|
||||
ec->publicKey.z = NULL;
|
||||
ec->privateKey = NULL;
|
||||
if (!getmppoint(&data, &len, &ec->publicKey)) {
|
||||
if (!get_point(src, &ec->publicKey)) {
|
||||
ecdsa_freekey(&ec->sshk);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1908,19 +1865,19 @@ static void ecdsa_private_blob(ssh_key *key, BinarySink *bs)
|
|||
}
|
||||
|
||||
static ssh_key *ecdsa_createkey(const ssh_keyalg *self,
|
||||
const void *pub_blob, int pub_len,
|
||||
const void *priv_blob, int priv_len)
|
||||
ptrlen pub, ptrlen priv)
|
||||
{
|
||||
BinarySource src[1];
|
||||
ssh_key *sshk;
|
||||
struct ec_key *ec;
|
||||
struct ec_point *publicKey;
|
||||
const char *pb = (const char *) priv_blob;
|
||||
|
||||
sshk = ecdsa_newkey(self, pub_blob, pub_len);
|
||||
sshk = ecdsa_newkey(self, pub);
|
||||
if (!sshk)
|
||||
return NULL;
|
||||
|
||||
ec = FROMFIELD(sshk, struct ec_key, sshk);
|
||||
BinarySource_BARE_INIT(src, priv.ptr, priv.len);
|
||||
|
||||
if (ec->publicKey.curve->type != EC_WEIERSTRASS
|
||||
&& ec->publicKey.curve->type != EC_EDWARDS) {
|
||||
|
@ -1929,9 +1886,9 @@ static ssh_key *ecdsa_createkey(const ssh_keyalg *self,
|
|||
}
|
||||
|
||||
if (ec->publicKey.curve->type == EC_EDWARDS) {
|
||||
ec->privateKey = getmp_le(&pb, &priv_len);
|
||||
ec->privateKey = get_mp_le(src);
|
||||
} else {
|
||||
ec->privateKey = getmp(&pb, &priv_len);
|
||||
ec->privateKey = get_mp_ssh2(src);
|
||||
}
|
||||
if (!ec->privateKey) {
|
||||
ecdsa_freekey(&ec->sshk);
|
||||
|
@ -1954,18 +1911,16 @@ static ssh_key *ecdsa_createkey(const ssh_keyalg *self,
|
|||
}
|
||||
|
||||
static ssh_key *ed25519_openssh_createkey(const ssh_keyalg *self,
|
||||
const unsigned char **blob, int *len)
|
||||
BinarySource *src)
|
||||
{
|
||||
struct ec_key *ec;
|
||||
struct ec_point *publicKey;
|
||||
const char *p, *q;
|
||||
int plen, qlen;
|
||||
ptrlen p, q;
|
||||
|
||||
getstring((const char**)blob, len, &p, &plen);
|
||||
if (!p)
|
||||
{
|
||||
p = get_string(src);
|
||||
q = get_string(src);
|
||||
if (get_err(src) || p.len != 32 || q.len != 64)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ec = snew(struct ec_key);
|
||||
|
||||
|
@ -1977,19 +1932,13 @@ static ssh_key *ed25519_openssh_createkey(const ssh_keyalg *self,
|
|||
ec->publicKey.z = NULL;
|
||||
ec->publicKey.y = NULL;
|
||||
|
||||
if (!decodepoint_ed(p, plen, &ec->publicKey))
|
||||
if (!decodepoint_ed(p.ptr, p.len, &ec->publicKey))
|
||||
{
|
||||
ecdsa_freekey(&ec->sshk);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
getstring((const char**)blob, len, &q, &qlen);
|
||||
if (!q || qlen != 64) {
|
||||
ecdsa_freekey(&ec->sshk);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ec->privateKey = bignum_from_bytes_le(q, 32);
|
||||
ec->privateKey = bignum_from_bytes_le(q.ptr, 32);
|
||||
|
||||
/* Check that private key generates public key */
|
||||
publicKey = ec_public(ec->privateKey, ec->publicKey.curve);
|
||||
|
@ -2009,7 +1958,7 @@ static ssh_key *ed25519_openssh_createkey(const ssh_keyalg *self,
|
|||
* correct as well, otherwise the key we think we've imported
|
||||
* won't behave identically to the way OpenSSH would have treated
|
||||
* it. */
|
||||
if (plen != 32 || 0 != memcmp(q + 32, p, 32)) {
|
||||
if (0 != memcmp((const char *)q.ptr + 32, p.ptr, 32)) {
|
||||
ecdsa_freekey(&ec->sshk);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -2054,22 +2003,16 @@ static void ed25519_openssh_fmtkey(ssh_key *key, BinarySink *bs)
|
|||
}
|
||||
|
||||
static ssh_key *ecdsa_openssh_createkey(const ssh_keyalg *self,
|
||||
const unsigned char **blob, int *len)
|
||||
BinarySource *src)
|
||||
{
|
||||
const struct ecsign_extra *extra =
|
||||
(const struct ecsign_extra *)self->extra;
|
||||
const char **b = (const char **) blob;
|
||||
const char *p;
|
||||
int slen;
|
||||
struct ec_key *ec;
|
||||
struct ec_curve *curve;
|
||||
struct ec_point *publicKey;
|
||||
|
||||
getstring(b, len, &p, &slen);
|
||||
get_string(src);
|
||||
|
||||
if (!p) {
|
||||
return NULL;
|
||||
}
|
||||
curve = extra->curve();
|
||||
assert(curve->type == EC_WEIERSTRASS);
|
||||
|
||||
|
@ -2081,7 +2024,7 @@ static ssh_key *ecdsa_openssh_createkey(const ssh_keyalg *self,
|
|||
ec->publicKey.x = NULL;
|
||||
ec->publicKey.y = NULL;
|
||||
ec->publicKey.z = NULL;
|
||||
if (!getmppoint(b, len, &ec->publicKey)) {
|
||||
if (!get_point(src, &ec->publicKey)) {
|
||||
ecdsa_freekey(&ec->sshk);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -2095,7 +2038,7 @@ static ssh_key *ecdsa_openssh_createkey(const ssh_keyalg *self,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
ec->privateKey = getmp(b, len);
|
||||
ec->privateKey = get_mp_ssh2(src);
|
||||
if (ec->privateKey == NULL)
|
||||
{
|
||||
ecdsa_freekey(&ec->sshk);
|
||||
|
@ -2147,14 +2090,13 @@ static void ecdsa_openssh_fmtkey(ssh_key *key, BinarySink *bs)
|
|||
put_mp_ssh2(bs, ec->privateKey);
|
||||
}
|
||||
|
||||
static int ecdsa_pubkey_bits(const ssh_keyalg *self,
|
||||
const void *blob, int len)
|
||||
static int ecdsa_pubkey_bits(const ssh_keyalg *self, ptrlen blob)
|
||||
{
|
||||
ssh_key *sshk;
|
||||
struct ec_key *ec;
|
||||
int ret;
|
||||
|
||||
sshk = ecdsa_newkey(self, blob, len);
|
||||
sshk = ecdsa_newkey(self, blob);
|
||||
if (!sshk)
|
||||
return -1;
|
||||
|
||||
|
@ -2165,39 +2107,35 @@ static int ecdsa_pubkey_bits(const ssh_keyalg *self,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int ecdsa_verifysig(ssh_key *key, const void *vsig, int siglen,
|
||||
const void *vdata, int datalen)
|
||||
static int ecdsa_verifysig(ssh_key *key, ptrlen sig, ptrlen data)
|
||||
{
|
||||
struct ec_key *ec = FROMFIELD(key, struct ec_key, sshk);
|
||||
const char *sig = (const char *)vsig;
|
||||
const char *data = (const char *)vdata;
|
||||
const struct ecsign_extra *extra =
|
||||
(const struct ecsign_extra *)ec->signalg->extra;
|
||||
const char *p;
|
||||
int slen;
|
||||
int digestLen;
|
||||
BinarySource src[1];
|
||||
ptrlen sigstr;
|
||||
int ret;
|
||||
|
||||
if (!ec->publicKey.x || !ec->publicKey.y || !ec->publicKey.curve)
|
||||
return 0;
|
||||
|
||||
/* Check the signature starts with the algorithm name */
|
||||
getstring(&sig, &siglen, &p, &slen);
|
||||
if (!p) {
|
||||
return 0;
|
||||
}
|
||||
if (!match_ssh_id(slen, p, ec->signalg->name)) {
|
||||
return 0;
|
||||
}
|
||||
BinarySource_BARE_INIT(src, sig.ptr, sig.len);
|
||||
|
||||
/* Check the signature starts with the algorithm name */
|
||||
if (!ptrlen_eq_string(get_string(src), ec->signalg->name))
|
||||
return 0;
|
||||
|
||||
sigstr = get_string(src);
|
||||
if (get_err(src))
|
||||
return 0;
|
||||
|
||||
getstring(&sig, &siglen, &p, &slen);
|
||||
if (!p) return 0;
|
||||
if (ec->publicKey.curve->type == EC_EDWARDS) {
|
||||
struct ec_point *r;
|
||||
int pointlen = ec->publicKey.curve->fieldBits / 8;
|
||||
Bignum s, h;
|
||||
|
||||
/* Check that the signature is two times the length of a point */
|
||||
if (slen != (ec->publicKey.curve->fieldBits / 8) * 2) {
|
||||
if (sigstr.len != pointlen * 2) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2211,25 +2149,23 @@ static int ecdsa_verifysig(ssh_key *key, const void *vsig, int siglen,
|
|||
if (!r) {
|
||||
return 0;
|
||||
}
|
||||
if (!decodepoint(p, ec->publicKey.curve->fieldBits / 8, r)) {
|
||||
if (!decodepoint(sigstr.ptr, pointlen, r)) {
|
||||
ec_point_free(r);
|
||||
return 0;
|
||||
}
|
||||
s = bignum_from_bytes_le((unsigned char*)p + (ec->publicKey.curve->fieldBits / 8),
|
||||
ec->publicKey.curve->fieldBits / 8);
|
||||
s = bignum_from_bytes_le(
|
||||
(const char *)sigstr.ptr + pointlen, pointlen);
|
||||
|
||||
/* Get the hash of the encoded value of R + encoded value of pk + message */
|
||||
{
|
||||
int i, pointlen;
|
||||
int i;
|
||||
unsigned char digest[512 / 8];
|
||||
SHA512_State hs;
|
||||
SHA512_Init(&hs);
|
||||
|
||||
pointlen = ec->publicKey.curve->fieldBits / 8;
|
||||
|
||||
/* Add encoded r (no need to encode it again, it was in
|
||||
* the signature) */
|
||||
put_data(&hs, p, pointlen);
|
||||
put_data(&hs, sigstr.ptr, pointlen);
|
||||
|
||||
/* Encode pk and add it */
|
||||
for (i = 0; i < pointlen - 1; ++i)
|
||||
|
@ -2239,7 +2175,7 @@ static int ecdsa_verifysig(ssh_key *key, const void *vsig, int siglen,
|
|||
(bignum_bit(ec->publicKey.x, 0) << 7)));
|
||||
|
||||
/* Add the message itself */
|
||||
put_data(&hs, data, datalen);
|
||||
put_data(&hs, data.ptr, data.len);
|
||||
|
||||
/* Get the hash */
|
||||
SHA512_Final(&hs, digest);
|
||||
|
@ -2291,20 +2227,23 @@ static int ecdsa_verifysig(ssh_key *key, const void *vsig, int siglen,
|
|||
} else {
|
||||
Bignum r, s;
|
||||
unsigned char digest[512 / 8];
|
||||
int digestLen;
|
||||
void *hashctx;
|
||||
|
||||
r = getmp(&p, &slen);
|
||||
if (!r) return 0;
|
||||
s = getmp(&p, &slen);
|
||||
if (!s) {
|
||||
BinarySource_BARE_INIT(src, sigstr.ptr, sigstr.len);
|
||||
|
||||
r = get_mp_ssh2(src);
|
||||
s = get_mp_ssh2(src);
|
||||
if (get_err(src)) {
|
||||
freebn(r);
|
||||
freebn(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
digestLen = extra->hash->hlen;
|
||||
assert(digestLen <= sizeof(digest));
|
||||
hashctx = extra->hash->init();
|
||||
put_data(extra->hash->sink(hashctx), data, datalen);
|
||||
put_data(extra->hash->sink(hashctx), data.ptr, data.len);
|
||||
extra->hash->final(hashctx, digest);
|
||||
|
||||
/* Verify the signature */
|
||||
|
|
|
@ -799,8 +799,9 @@ struct ssh2_userkey *ssh2_load_userkey(const Filename *filename,
|
|||
ret = snew(struct ssh2_userkey);
|
||||
ret->alg = alg;
|
||||
ret->comment = comment;
|
||||
ret->data = alg->createkey(alg, public_blob->u, public_blob->len,
|
||||
private_blob->u, private_blob->len);
|
||||
ret->data = alg->createkey(
|
||||
alg, make_ptrlen(public_blob->u, public_blob->len),
|
||||
make_ptrlen(private_blob->u, private_blob->len));
|
||||
if (!ret->data) {
|
||||
sfree(ret);
|
||||
ret = NULL;
|
||||
|
@ -1509,7 +1510,7 @@ char *ssh2_fingerprint_blob(const void *blob, int bloblen)
|
|||
if (!get_err(src)) {
|
||||
alg = find_pubkey_alg_len(algname);
|
||||
if (alg) {
|
||||
int bits = alg->pubkey_bits(alg, blob, bloblen);
|
||||
int bits = alg->pubkey_bits(alg, make_ptrlen(blob, bloblen));
|
||||
return dupprintf("%.*s %d %s", PTRLEN_PRINTF(algname),
|
||||
bits, fingerprint_str);
|
||||
} else {
|
||||
|
|
137
sshrsa.c
137
sshrsa.c
|
@ -520,62 +520,27 @@ void freersakey(struct RSAKey *key)
|
|||
* Implementation of the ssh-rsa signing key type.
|
||||
*/
|
||||
|
||||
static void getstring(const char **data, int *datalen,
|
||||
const char **p, int *length)
|
||||
{
|
||||
*p = NULL;
|
||||
if (*datalen < 4)
|
||||
return;
|
||||
*length = toint(GET_32BIT(*data));
|
||||
if (*length < 0)
|
||||
return;
|
||||
*datalen -= 4;
|
||||
*data += 4;
|
||||
if (*datalen < *length)
|
||||
return;
|
||||
*p = *data;
|
||||
*data += *length;
|
||||
*datalen -= *length;
|
||||
}
|
||||
static Bignum getmp(const char **data, int *datalen)
|
||||
{
|
||||
const char *p;
|
||||
int length;
|
||||
Bignum b;
|
||||
|
||||
getstring(data, datalen, &p, &length);
|
||||
if (!p)
|
||||
return NULL;
|
||||
b = bignum_from_bytes(p, length);
|
||||
return b;
|
||||
}
|
||||
|
||||
static void rsa2_freekey(ssh_key *key); /* forward reference */
|
||||
|
||||
static ssh_key *rsa2_newkey(const ssh_keyalg *self,
|
||||
const void *vdata, int len)
|
||||
static ssh_key *rsa2_newkey(const ssh_keyalg *self, ptrlen data)
|
||||
{
|
||||
const char *p;
|
||||
const char *data = (const char *)vdata;
|
||||
int slen;
|
||||
BinarySource src[1];
|
||||
struct RSAKey *rsa;
|
||||
|
||||
rsa = snew(struct RSAKey);
|
||||
getstring(&data, &len, &p, &slen);
|
||||
|
||||
if (!p || slen != 7 || memcmp(p, "ssh-rsa", 7)) {
|
||||
sfree(rsa);
|
||||
BinarySource_BARE_INIT(src, data.ptr, data.len);
|
||||
if (!ptrlen_eq_string(get_string(src), "ssh-rsa"))
|
||||
return NULL;
|
||||
}
|
||||
rsa->exponent = getmp(&data, &len);
|
||||
rsa->modulus = getmp(&data, &len);
|
||||
|
||||
rsa = snew(struct RSAKey);
|
||||
rsa->exponent = get_mp_ssh2(src);
|
||||
rsa->modulus = get_mp_ssh2(src);
|
||||
rsa->private_exponent = NULL;
|
||||
rsa->p = rsa->q = rsa->iqmp = NULL;
|
||||
rsa->comment = NULL;
|
||||
|
||||
if (!rsa->exponent || !rsa->modulus) {
|
||||
rsa2_freekey(&rsa->sshk);
|
||||
return NULL;
|
||||
if (get_err(src)) {
|
||||
rsa2_freekey(&rsa->sshk);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &rsa->sshk;
|
||||
|
@ -620,24 +585,24 @@ static void rsa2_private_blob(ssh_key *key, BinarySink *bs)
|
|||
}
|
||||
|
||||
static ssh_key *rsa2_createkey(const ssh_keyalg *self,
|
||||
const void *pub_blob, int pub_len,
|
||||
const void *priv_blob, int priv_len)
|
||||
ptrlen pub, ptrlen priv)
|
||||
{
|
||||
BinarySource src[1];
|
||||
ssh_key *sshk;
|
||||
struct RSAKey *rsa;
|
||||
const char *pb = (const char *) priv_blob;
|
||||
|
||||
sshk = rsa2_newkey(self, pub_blob, pub_len);
|
||||
sshk = rsa2_newkey(self, pub);
|
||||
if (!sshk)
|
||||
return NULL;
|
||||
|
||||
rsa = FROMFIELD(sshk, struct RSAKey, sshk);
|
||||
rsa->private_exponent = getmp(&pb, &priv_len);
|
||||
rsa->p = getmp(&pb, &priv_len);
|
||||
rsa->q = getmp(&pb, &priv_len);
|
||||
rsa->iqmp = getmp(&pb, &priv_len);
|
||||
BinarySource_BARE_INIT(src, priv.ptr, priv.len);
|
||||
rsa->private_exponent = get_mp_ssh2(src);
|
||||
rsa->p = get_mp_ssh2(src);
|
||||
rsa->q = get_mp_ssh2(src);
|
||||
rsa->iqmp = get_mp_ssh2(src);
|
||||
|
||||
if (!rsa_verify(rsa)) {
|
||||
if (get_err(src) || !rsa_verify(rsa)) {
|
||||
rsa2_freekey(&rsa->sshk);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -646,28 +611,21 @@ static ssh_key *rsa2_createkey(const ssh_keyalg *self,
|
|||
}
|
||||
|
||||
static ssh_key *rsa2_openssh_createkey(const ssh_keyalg *self,
|
||||
const unsigned char **blob, int *len)
|
||||
BinarySource *src)
|
||||
{
|
||||
const char **b = (const char **) blob;
|
||||
struct RSAKey *rsa;
|
||||
|
||||
rsa = snew(struct RSAKey);
|
||||
rsa->comment = NULL;
|
||||
|
||||
rsa->modulus = getmp(b, len);
|
||||
rsa->exponent = getmp(b, len);
|
||||
rsa->private_exponent = getmp(b, len);
|
||||
rsa->iqmp = getmp(b, len);
|
||||
rsa->p = getmp(b, len);
|
||||
rsa->q = getmp(b, len);
|
||||
rsa->modulus = get_mp_ssh2(src);
|
||||
rsa->exponent = get_mp_ssh2(src);
|
||||
rsa->private_exponent = get_mp_ssh2(src);
|
||||
rsa->iqmp = get_mp_ssh2(src);
|
||||
rsa->p = get_mp_ssh2(src);
|
||||
rsa->q = get_mp_ssh2(src);
|
||||
|
||||
if (!rsa->modulus || !rsa->exponent || !rsa->private_exponent ||
|
||||
!rsa->iqmp || !rsa->p || !rsa->q) {
|
||||
rsa2_freekey(&rsa->sshk);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!rsa_verify(rsa)) {
|
||||
if (get_err(src) || !rsa_verify(rsa)) {
|
||||
rsa2_freekey(&rsa->sshk);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -687,14 +645,13 @@ static void rsa2_openssh_fmtkey(ssh_key *key, BinarySink *bs)
|
|||
put_mp_ssh2(bs, rsa->q);
|
||||
}
|
||||
|
||||
static int rsa2_pubkey_bits(const ssh_keyalg *self,
|
||||
const void *blob, int len)
|
||||
static int rsa2_pubkey_bits(const ssh_keyalg *self, ptrlen pub)
|
||||
{
|
||||
ssh_key *sshk;
|
||||
struct RSAKey *rsa;
|
||||
int ret;
|
||||
|
||||
sshk = rsa2_newkey(self, blob, len);
|
||||
sshk = rsa2_newkey(self, pub);
|
||||
if (!sshk)
|
||||
return -1;
|
||||
|
||||
|
@ -736,24 +693,32 @@ static const unsigned char asn1_weird_stuff[] = {
|
|||
|
||||
#define ASN1_LEN ( (int) sizeof(asn1_weird_stuff) )
|
||||
|
||||
static int rsa2_verifysig(ssh_key *key, const void *vsig, int siglen,
|
||||
const void *data, int datalen)
|
||||
static int rsa2_verifysig(ssh_key *key, ptrlen sig, ptrlen data)
|
||||
{
|
||||
struct RSAKey *rsa = FROMFIELD(key, struct RSAKey, sshk);
|
||||
const char *sig = (const char *)vsig;
|
||||
BinarySource src[1];
|
||||
ptrlen type, in_pl;
|
||||
Bignum in, out;
|
||||
const char *p;
|
||||
int slen;
|
||||
int bytes, i, j, ret;
|
||||
unsigned char hash[20];
|
||||
|
||||
getstring(&sig, &siglen, &p, &slen);
|
||||
if (!p || slen != 7 || memcmp(p, "ssh-rsa", 7)) {
|
||||
BinarySource_BARE_INIT(src, sig.ptr, sig.len);
|
||||
type = get_string(src);
|
||||
/*
|
||||
* RFC 4253 section 6.6: the signature integer in an ssh-rsa
|
||||
* signature is 'without lengths or padding'. That is, we _don't_
|
||||
* expect the usual leading zero byte if the topmost bit of the
|
||||
* first byte is set. (However, because of the possibility of
|
||||
* BUG_SSH2_RSA_PADDING at the other end, we tolerate it if it's
|
||||
* there.) So we can't use get_mp_ssh2, which enforces that
|
||||
* leading-byte scheme; instead we use get_string and
|
||||
* bignum_from_bytes, which will tolerate anything.
|
||||
*/
|
||||
in_pl = get_string(src);
|
||||
if (get_err(src) || !ptrlen_eq_string(type, "ssh-rsa"))
|
||||
return 0;
|
||||
}
|
||||
in = getmp(&sig, &siglen);
|
||||
if (!in)
|
||||
return 0;
|
||||
|
||||
in = bignum_from_bytes(in_pl.ptr, in_pl.len);
|
||||
out = modpow(in, rsa->exponent, rsa->modulus);
|
||||
freebn(in);
|
||||
|
||||
|
@ -777,7 +742,7 @@ static int rsa2_verifysig(ssh_key *key, const void *vsig, int siglen,
|
|||
ret = 0;
|
||||
}
|
||||
/* Finally, we expect to see the SHA-1 hash of the signed data. */
|
||||
SHA_Simple(data, datalen, hash);
|
||||
SHA_Simple(data.ptr, data.len, hash);
|
||||
for (i = 19, j = 0; i >= 0; i--, j++) {
|
||||
if (bignum_byte(out, i) != hash[j])
|
||||
ret = 0;
|
||||
|
@ -846,7 +811,7 @@ const ssh_keyalg ssh_rsa = {
|
|||
|
||||
struct RSAKey *ssh_rsakex_newkey(const void *data, int len)
|
||||
{
|
||||
ssh_key *sshk = rsa2_newkey(&ssh_rsa, data, len);
|
||||
ssh_key *sshk = rsa2_newkey(&ssh_rsa, make_ptrlen(data, len));
|
||||
if (!sshk)
|
||||
return NULL;
|
||||
return FROMFIELD(sshk, struct RSAKey, sshk);
|
||||
|
|
Загрузка…
Ссылка в новой задаче