Because site wants to first unpick the packet, and only later actually
check the signature, we provide two entrypoints. The first, `unpick',
basically just computes the length. So the result of `unpick' is
simply a note of the part of the buffer which contains the signature.
The alternative would be to have site.c handle the length, so there
would be one entrypoint `check' which would get a byte block. This
would move complexity from the `unpick'/`check' interface to the
`sign' interface (which would have to negotiate about space). It
would mean that for algorithms where signatures are of fixed size, we
couldn't omit the length field.
rsa.c needs to do some shenanigans: because it wants to use
mpz_set_str (for historical reasons), it needs the buffer to be
nul-terminated. So `unpick' checks that there will be a spare byte
afterwards into which we can write the nul. `check' writes the nul -
and puts the previous character back, so that we don't have to write
weird stuff in the algorithm api. Doing better than this would be
turd-polishing since this algorithm is obsolete.
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
+static bool_t rsa_sig_unpick(void *sst, struct buffer_if *msg,
+ struct alg_msg_data *sig)
+{
+ uint8_t *lp = buf_unprepend(msg, 2);
+ if (!lp) return False;
+ sig->siglen = get_uint16(lp);
+ sig->sigstart = buf_unprepend(msg, sig->siglen);
+ if (!sig->sigstart) return False;
+
+ /* In `rsa_sig_check' below, we assume that we can write a nul
+ * terminator following the signature. Make sure there's enough space.
+ */
+ if (msg->start >= msg->base + msg->alloclen)
+ return False;
+
+ return True;
+}
+
static sig_checksig_fn rsa_sig_check;
static bool_t rsa_sig_check(void *sst, uint8_t *data, int32_t datalen,
static sig_checksig_fn rsa_sig_check;
static bool_t rsa_sig_check(void *sst, uint8_t *data, int32_t datalen,
+ const struct alg_msg_data *sig)
{
struct rsapub *st=sst;
MP_INT a, b, c;
{
struct rsapub *st=sst;
MP_INT a, b, c;
emsa_pkcs1(&st->n, &a, data, datalen);
emsa_pkcs1(&st->n, &a, data, datalen);
- mpz_set_str(&b, signature, 16);
+ /* Terminate signature with a '0' - already checked that this will fit */
+ int save = sig->sigstart[sig->siglen];
+ sig->sigstart[sig->siglen] = 0;
+ mpz_set_str(&b, sig->sigstart, 16);
+ sig->sigstart[sig->siglen] = save;
mpz_powm(&c, &b, &st->e, &st->n);
mpz_powm(&c, &b, &st->e, &st->n);
st->cl.apply=NULL;
st->cl.interface=&st->ops;
st->ops.st=st;
st->cl.apply=NULL;
st->cl.interface=&st->ops;
st->ops.st=st;
+ st->ops.unpick=rsa_sig_unpick;
st->ops.check=rsa_sig_check;
st->loc=loc;
st->ops.check=rsa_sig_check;
st->loc=loc;
+struct alg_msg_data {
+ uint8_t *sigstart;
+ int32_t siglen;
+};
+
/* PURE closure requires no interface */
/* RESOLVER interface */
/* PURE closure requires no interface */
/* RESOLVER interface */
/* SIGPUBKEY interface */
/* SIGPUBKEY interface */
+typedef bool_t sig_unpick_fn(void *sst, struct buffer_if *msg,
+ struct alg_msg_data *sig);
typedef bool_t sig_checksig_fn(void *st, uint8_t *data, int32_t datalen,
typedef bool_t sig_checksig_fn(void *st, uint8_t *data, int32_t datalen,
+ const struct alg_msg_data *sig);
struct sigpubkey_if {
void *st;
struct sigpubkey_if {
void *st;
sig_checksig_fn *check;
};
sig_checksig_fn *check;
};
int32_t pklen;
char *pk;
int32_t hashlen;
int32_t pklen;
char *pk;
int32_t hashlen;
- int32_t siglen;
- char *sig;
+ struct alg_msg_data sig;
};
static int32_t wait_timeout(struct site *st) {
};
static int32_t wait_timeout(struct site *st) {
CHECK_AVAIL(msg,m->pklen);
m->pk=buf_unprepend(msg,m->pklen);
m->hashlen=msg->start-m->hashstart;
CHECK_AVAIL(msg,m->pklen);
m->pk=buf_unprepend(msg,m->pklen);
m->hashlen=msg->start-m->hashstart;
- CHECK_AVAIL(msg,2);
- m->siglen=buf_unprepend_uint16(msg);
- CHECK_AVAIL(msg,m->siglen);
- m->sig=buf_unprepend(msg,m->siglen);
- CHECK_EMPTY(msg);
- /* In `process_msg3_msg4' below, we assume that we can write a nul
- * terminator following the signature. Make sure there's enough space.
- */
- if (msg->start >= msg->base + msg->alloclen)
+ if (!st->pubkey->unpick(st->pubkey->st,msg,&m->sig)) {
+ }
+
+ CHECK_EMPTY(msg);
hst=st->hash->init();
st->hash->update(hst,m->hashstart,m->hashlen);
st->hash->final(hst,hash);
hst=st->hash->init();
st->hash->update(hst,m->hashstart,m->hashlen);
st->hash->final(hst,hash);
- /* Terminate signature with a '0' - already checked that this will fit */
- m->sig[m->siglen]=0;
- if (!st->pubkey->check(st->pubkey->st,hash,st->hash->len,m->sig)) {
+ if (!st->pubkey->check(st->pubkey->st,
+ hash,st->hash->len,
+ &m->sig)) {
slog(st,LOG_SEC,"msg3/msg4 signature failed check!");
free(hash);
return False;
slog(st,LOG_SEC,"msg3/msg4 signature failed check!");
free(hash);
return False;