* uint VARNAME/VALUE (VARNAME if ul2bitfields;
* ulong VARNAME/VALUE VALUE if bitfields2ul)
*
+ * Error codes
+ *
+ * HBYTES BLOCKCIPHER CRYPTFAIL CRYPT block cipher mode failed somehow (!)
+ * HBYTES BLOCKCIPHER CRYPTFAIL MAC HMAC failed somehow (!)
+ * HBYTES BLOCKCIPHER LENGTH block cipher input has unsuitable length
+ * HBYTES BLOCKCIPHER PARAMS key or iv not suitable
+ * HBYTES HMAC PARAMS key, input or output size not suitable
+ * HBYTES LENGTH OVERRUN block too long
+ * HBYTES LENGTH RANGE input length or offset is -ve or silly
+ * HBYTES LENGTH UNDERRUN block too short (or offset too big)
+ * HBYTES SYNTAX supposed hex block had wrong syntax
+ * HBYTES VALUE OVERFLOW value to be conv'd to hex too big/long
+ * SOCKADDR AFUNIX LENGTH path for AF_UNIX socket too long
+ * SOCKADDR SYNTAX IPV4 bad IPv4 socket address &/or port
+ * SOCKADDR SYNTAX OTHER bad socket addr, couldn't tell what kind
+ * ULONG BITCOUNT NEGATIVE -ve bitcount specified where not allowed
+ * ULONG BITCOUNT OVERRUN attempt to use more than 32 bits
+ * ULONG BITCOUNT UNDERRUN bitfields add up to less than 32
+ * ULONG VALUE NEGATIVE attempt convert -ve integers to ulong
+ * ULONG VALUE OVERFLOW converted value does not fit in result
+ *
* Refs: HMAC: RFC2104
*/
/* from hook.c */
-int staticerr(Tcl_Interp *ip, const char *m);
+int staticerr(Tcl_Interp *ip, const char *m, const char *ec);
int posixerr(Tcl_Interp *ip, int errnoval, const char *m);
void objfreeir(Tcl_Obj *o);
int get_urandom(Tcl_Interp *ip, Byte *buffer, int l);
#include "hbytes.h"
#include "tables.h"
-int staticerr(Tcl_Interp *ip, const char *m) {
+int staticerr(Tcl_Interp *ip, const char *m, const char *ec) {
Tcl_SetResult(ip, (char*)m, TCL_STATIC);
+ if (ec) Tcl_SetObjErrorCode(ip, Tcl_NewStringObj(ec,-1));
return TCL_ERROR;
}
objfreeir(o);
if (l & 1) return staticerr(ip, "hbytes: conversion from hex:"
- " odd length in hex");
+ " odd length in hex", "HBYTES SYNTAX");
startbytes= bytes= hbytes_arrayspace(OBJ_HBYTES(o), l/2);
if (ep != cbuf+2) {
hbytes_free(OBJ_HBYTES(o));
return staticerr(ip, "hbytes: conversion from hex:"
- " bad hex digit");
+ " bad hex digit", "HBYTES SYNTAX");
}
l -= 2;
}
sub_l= hbytes_len(&sub);
if (start < 0)
- return staticerr(ip, "hbytes overwrite start -ve");
+ return staticerr(ip, "hbytes overwrite start -ve",
+ "HBYTES LENGTH RANGE");
if (start + sub_l > hbytes_len(v.hb))
- return staticerr(ip, "hbytes overwrite out of range");
+ return staticerr(ip, "hbytes overwrite out of range",
+ "HBYTES LENGTH UNDERRUN");
memcpy(hbytes_data(v.hb) + start, hbytes_data(&sub), sub_l);
return TCL_OK;
}
const Byte *sub_d;
sub_l= hbytes_len(&sub);
- if (count < 0) return staticerr(ip, "hbytes repeat count -ve");
- if (count > INT_MAX/sub_l) return staticerr(ip, "hbytes repeat too long");
+ if (count < 0) return staticerr(ip, "hbytes repeat count -ve",
+ "HBYTES LENGTH RANGE");
+ if (count > INT_MAX/sub_l) return staticerr(ip, "hbytes repeat too long", 0);
data= hbytes_arrayspace(result, sub_l*count);
sub_d= hbytes_data(&sub);
int l;
l= hbytes_len(&v);
- if (start<0 || size<0 || l<start+size)
- return staticerr(ip, "hbytes range subscripts out of range");
+ if (start<0 || size<0)
+ return staticerr(ip,"hbytes range subscript(s) -ve","HBYTES LENGTH RANGE");
+ if (l<start+size)
+ return staticerr(ip, "hbytes range subscripts too big",
+ "HBYTES LENGTH UNDERRUN");
data= hbytes_data(&v);
hbytes_array(result, data+start, size);
l= hbytes_len(&hex);
if (l>2)
- return staticerr(ip, "hbytes h2ushort input more than 4 hex digits");
+ return staticerr(ip, "hbytes h2ushort input more than 4 hex digits",
+ "HBYTES VALUE OVERFLOW");
data= hbytes_data(&hex);
*result= data[l-1] | (l>1 ? data[0]<<8 : 0);
uint16_t us;
if (input > 0x0ffff)
- return staticerr(ip, "hbytes ushort2h input >2^16");
+ return staticerr(ip, "hbytes ushort2h input >2^16",
+ "HBYTES VALUE OVERFLOW");
us= htons(input);
hbytes_array(result,(const Byte*)&us,2);
return posixerr(ip,errno,"read " URANDOM);
} else {
assert(feof(urandom));
- return staticerr(ip, URANDOM " gave eof!");
+ return staticerr(ip, URANDOM " gave eof!", 0);
}
}
} else {
rc= Tcl_GetIntFromObj(ip, block, &blocksize); if (rc) return rc;
if (blocksize < 1 || blocksize > 255)
- return staticerr(ip, "block size out of pkcs#5 range 1..255");
+ return staticerr(ip, "block size out of pkcs#5 range 1..255", 0);
}
if (meth->pad) {
CiphKeyValue *key;
if (data_len % alg->blocksize)
- return staticerr(ip, "block cipher input not whole number of blocks");
+ return staticerr(ip, "block cipher input not whole number of blocks",
+ "HBYTES BLOCKCIPHER LENGTH");
want_bufferslen= alg->blocksize * (mode->buf_blocks + mode->iv_blocks);
key= get_key(ip, key_obj, alg, want_bufferslen); if (!key) return TCL_ERROR;
|| !decrypt) ? &key->alpha : &key->beta;
sched= *schedp;
if (!sched) {
- if (key->valuelen < alg->key_min) return staticerr(ip, "key too short");
- if (key->valuelen > alg->key_max) return staticerr(ip, "key too long");
+ if (key->valuelen < alg->key_min)
+ return staticerr(ip, "key too short", "HBYTES BLOCKCIPHER PARAMS");
+ if (key->valuelen > alg->key_max)
+ return staticerr(ip, "key too long", "HBYTES BLOCKCIPHER PARAMS");
sched= TALLOC(alg->schedule_size);
(decrypt ? &alg->decrypt : &alg->encrypt)->make_schedule
want_iv= alg->blocksize * mode->iv_blocks;
if (!want_iv) {
if (!hbytes_issentinel(iv))
- return staticerr(ip,"iv supplied but mode does not take one");
+ return staticerr(ip,"iv supplied but mode does not take one", 0);
} else if (hbytes_issentinel(iv)) {
- if (decrypt) return staticerr(ip,"must supply iv when decrypting");
+ if (decrypt) return staticerr(ip,"must supply iv when decrypting", 0);
rc= get_urandom(ip, key->buffers, want_iv);
if (rc) return rc;
} else {
int iv_supplied= hbytes_len(iv);
if (iv_supplied > want_iv)
- return staticerr(ip, "iv too large for algorithm and mode");
+ return staticerr(ip, "iv too large for algorithm and mode",
+ "HBYTES BLOCKCIPHER PARAMS");
memcpy(key->buffers, hbytes_data(iv), iv_supplied);
memset(key->buffers + iv_supplied, 0, want_iv - iv_supplied);
}
int nblocks;
if (!mode->encrypt)
- return staticerr(ip, "mode does not support encrypt/decrypt");
+ return staticerr(ip, "mode does not support encrypt/decrypt", 0);
rc= blockcipher_prep(ip,key_obj,&iv,!encrypt,
alg,mode, hbytes_len(v.hb),
(hbytes_data(v.hb), nblocks, ivbuf, buffers, alg, encrypt, sched);
if (failure)
- return staticerr(ip, failure);
+ return staticerr(ip, failure, "HBYTES BLOCKCIPHER CRYPTFAIL CRYPT");
hbytes_array(result, ivbuf, iv_lenbytes);
int rc;
if (!mode->mac)
- return staticerr(ip, "mode does not support mac generation");
+ return staticerr(ip, "mode does not support mac generation", 0);
rc= blockcipher_prep(ip,key_obj,&iv,0,
alg,mode, hbytes_len(&msg),
failure= mode->mac(hbytes_data(&msg), nblocks, ivbuf, buffers, alg, sched);
if (failure)
- return staticerr(ip,failure);
+ return staticerr(ip,failure, "HBYTES BLOCKCIPHER CRYPTFAIL MAC");
hbytes_array(result, buffers, alg->blocksize * mode->mac_blocks);
return TCL_OK;
}
-static void dbuf(const char *m, const Byte *a, int l) {
- fprintf(stderr,"dbuf %s l=%d ",m,l);
- while (l-->0) fprintf(stderr,"%02x",*a++);
- putc('\n',stderr);
-}
-
int do_hbytes_hmac(ClientData cd, Tcl_Interp *ip, const HashAlgInfo *alg,
HBytes_Value message, Tcl_Obj *key_obj,
Tcl_Obj *maclen_obj, HBytes_Value *result) {
if (maclen_obj) {
rc= Tcl_GetIntFromObj(ip, maclen_obj, &ml); if (rc) return rc;
if (ml<0 || ml>alg->hashsize)
- return staticerr(ip, "requested hmac output size out of range");
+ return staticerr(ip, "requested hmac output size out of range",
+ "HBYTES HMAC PARAMS");
} else {
ml= alg->hashsize;
}
assert(!key->beta);
if (key->valuelen > alg->blocksize)
- return staticerr(ip, "key to hmac longer than hash block size");
+ return staticerr(ip, "key to hmac longer than hash block size",
+ "HBYTES HMAC PARAMS");
-dbuf("start key",key->value,key->valuelen);
memcpy(key->buffers, key->value, key->valuelen);
memset(key->buffers + key->valuelen, 0, alg->blocksize - key->valuelen);
for (i=0; i<alg->blocksize; i++) key->buffers[i] ^= 0x36;
key->alpha= TALLOC(alg->statesize);
alg->init(key->alpha);
-dbuf("inner key",key->buffers,alg->blocksize);
alg->update(key->alpha, key->buffers, alg->blocksize);
key->beta= TALLOC(alg->statesize);
alg->init(key->beta);
for (i=0; i<alg->blocksize; i++) key->buffers[i] ^= (0x5c ^ 0x36);
alg->update(key->beta, key->buffers, alg->blocksize);
-dbuf("inner key",key->buffers,alg->blocksize);
}
assert(key->beta);
memcpy(key->buffers, key->alpha, alg->statesize);
alg->update(key->buffers, hbytes_data(&message), hbytes_len(&message));
alg->final(key->buffers, dest);
-dbuf("inner hash",dest,alg->hashsize);
memcpy(key->buffers, key->beta, alg->statesize);
alg->update(key->buffers, dest, alg->hashsize);
alg->final(key->buffers, dest);
-dbuf("outer hash",dest,alg->hashsize);
hbytes_unappend(result, alg->hashsize - ml);
0,
sockaddr_addr(&remote), sockaddr_len(&remote));
if (r==-1) return posixerr(ip,errno,"sendto");
- else if (r!=l) return staticerr(ip,"sendto gave wrong answer");
+ else if (r!=l) return staticerr(ip,"sendto gave wrong answer",0);
return TCL_OK;
}
sockix= o->internalRep.longValue;
if (sockix >= n_socks || !(sock= socks[sockix]))
- return staticerr(ip,"dgram socket not open");
+ return staticerr(ip,"dgram socket not open",0);
assert(socks[sockix]->ix == sockix);
char *ep, *str;
str= Tcl_GetStringFromObj(o,0);
- if (memcmp(str,"dgramsock",9)) return staticerr(ip,"bad dgram socket id");
+ if (memcmp(str,"dgramsock",9)) return staticerr(ip,"bad dgram socket id",0);
errno=0; ul=strtoul(str+9,&ep,10);
- if (errno || *ep) return staticerr(ip,"bad dgram socket id number");
- if (ul > INT_MAX) return staticerr(ip,"out of range dgram socket id");
+ if (errno || *ep) return staticerr(ip,"bad dgram socket id number",0);
+ if (ul > INT_MAX) return staticerr(ip,"out of range dgram socket id",0);
objfreeir(o);
o->internalRep.longValue= ul;
else { assert(str[0]=='/' && str[1]!='/'); path=str; }
if (strlen(str) >= sizeof(s.sun.sun_path))
- return staticerr(ip, "AF_UNIX path too long");
+ return staticerr(ip, "AF_UNIX path too long", "SOCKADDR AFUNIX LENGTH");
strcpy(s.sun.sun_path, path);
}
TFREE(copy);
- if (!iprv) return staticerr(ip, "bad IPv4 address syntax");
+ if (!iprv)
+ return staticerr(ip, "bad IPv4 address syntax", "SOCKADDR SYNTAX IPV4");
comma++;
if (!strcmp(comma,"*")) {
s.sin.sin_port= 0;
} else {
errno=0; port_l=strtoul(comma,&ep,10);
- if (errno || *ep) return staticerr(ip, "bad IPv4 port");
- if (port_l > 65535) return staticerr(ip, "IPv4 port out of range");
+ if (errno || *ep)
+ return staticerr(ip, "bad IPv4 port", "SOCKADDR SYNTAX IPV4");
+ if (port_l > 65535)
+ return staticerr(ip, "IPv4 port out of range", "SOCKADDR SYNTAX IPV4");
s.sin.sin_port= htons(port_l);
}
} else {
- return staticerr(ip, "bad socket address syntax");
+ return staticerr(ip, "bad socket address syntax", "SOCKADDR SYNTAX OTHER");
}
return TCL_OK;
}
-static int underrun(Tcl_Interp *ip) { return staticerr(ip,"data underrun"); }
+static int underrun(Tcl_Interp *ip) {
+ return staticerr(ip,"data underrun","HBYTES LENGTH UNDERRUN");
+}
int do_hbytes_unprepend(ClientData cd, Tcl_Interp *ip,
HBytes_Var v, int preflength, HBytes_Value *result) {
* uint VARNAME/VALUE (VARNAME if ul2bitfields;
* ulong VARNAME/VALUE VALUE if bitfields2ul)
*
+ * Error codes
+ *
+ * HBYTES BLOCKCIPHER CRYPTFAIL CRYPT block cipher mode failed somehow (!)
+ * HBYTES BLOCKCIPHER CRYPTFAIL MAC HMAC failed somehow (!)
+ * HBYTES BLOCKCIPHER LENGTH block cipher input has unsuitable length
+ * HBYTES BLOCKCIPHER PARAMS key or iv not suitable
+ * HBYTES HMAC PARAMS key, input or output size not suitable
+ * HBYTES LENGTH OVERRUN block too long
+ * HBYTES LENGTH RANGE input length or offset is -ve or silly
+ * HBYTES LENGTH UNDERRUN block too short (or offset too big)
+ * HBYTES SYNTAX supposed hex block had wrong syntax
+ * HBYTES VALUE OVERFLOW value to be conv'd to hex too big/long
+ * SOCKADDR AFUNIX LENGTH path for AF_UNIX socket too long
+ * SOCKADDR SYNTAX IPV4 bad IPv4 socket address &/or port
+ * SOCKADDR SYNTAX OTHER bad socket addr, couldn't tell what kind
+ * ULONG BITCOUNT NEGATIVE -ve bitcount specified where not allowed
+ * ULONG BITCOUNT OVERRUN attempt to use more than 32 bits
+ * ULONG BITCOUNT UNDERRUN bitfields add up to less than 32
+ * ULONG VALUE NEGATIVE attempt convert -ve integers to ulong
+ * ULONG VALUE OVERFLOW converted value does not fit in result
+ *
* Refs: HMAC: RFC2104
*/
/* from hook.c */
-int staticerr(Tcl_Interp *ip, const char *m);
+int staticerr(Tcl_Interp *ip, const char *m, const char *ec);
int posixerr(Tcl_Interp *ip, int errnoval, const char *m);
void objfreeir(Tcl_Obj *o);
int get_urandom(Tcl_Interp *ip, Byte *buffer, int l);
#include "hbytes.h"
#include "tables.h"
-int staticerr(Tcl_Interp *ip, const char *m) {
+int staticerr(Tcl_Interp *ip, const char *m, const char *ec) {
Tcl_SetResult(ip, (char*)m, TCL_STATIC);
+ if (ec) Tcl_SetObjErrorCode(ip, Tcl_NewStringObj(ec,-1));
return TCL_ERROR;
}
objfreeir(o);
if (l & 1) return staticerr(ip, "hbytes: conversion from hex:"
- " odd length in hex");
+ " odd length in hex", "HBYTES SYNTAX");
startbytes= bytes= hbytes_arrayspace(OBJ_HBYTES(o), l/2);
if (ep != cbuf+2) {
hbytes_free(OBJ_HBYTES(o));
return staticerr(ip, "hbytes: conversion from hex:"
- " bad hex digit");
+ " bad hex digit", "HBYTES SYNTAX");
}
l -= 2;
}
sub_l= hbytes_len(&sub);
if (start < 0)
- return staticerr(ip, "hbytes overwrite start -ve");
+ return staticerr(ip, "hbytes overwrite start -ve",
+ "HBYTES LENGTH RANGE");
if (start + sub_l > hbytes_len(v.hb))
- return staticerr(ip, "hbytes overwrite out of range");
+ return staticerr(ip, "hbytes overwrite out of range",
+ "HBYTES LENGTH UNDERRUN");
memcpy(hbytes_data(v.hb) + start, hbytes_data(&sub), sub_l);
return TCL_OK;
}
const Byte *sub_d;
sub_l= hbytes_len(&sub);
- if (count < 0) return staticerr(ip, "hbytes repeat count -ve");
- if (count > INT_MAX/sub_l) return staticerr(ip, "hbytes repeat too long");
+ if (count < 0) return staticerr(ip, "hbytes repeat count -ve",
+ "HBYTES LENGTH RANGE");
+ if (count > INT_MAX/sub_l) return staticerr(ip, "hbytes repeat too long", 0);
data= hbytes_arrayspace(result, sub_l*count);
sub_d= hbytes_data(&sub);
int l;
l= hbytes_len(&v);
- if (start<0 || size<0 || l<start+size)
- return staticerr(ip, "hbytes range subscripts out of range");
+ if (start<0 || size<0)
+ return staticerr(ip,"hbytes range subscript(s) -ve","HBYTES LENGTH RANGE");
+ if (l<start+size)
+ return staticerr(ip, "hbytes range subscripts too big",
+ "HBYTES LENGTH UNDERRUN");
data= hbytes_data(&v);
hbytes_array(result, data+start, size);
l= hbytes_len(&hex);
if (l>2)
- return staticerr(ip, "hbytes h2ushort input more than 4 hex digits");
+ return staticerr(ip, "hbytes h2ushort input more than 4 hex digits",
+ "HBYTES VALUE OVERFLOW");
data= hbytes_data(&hex);
*result= data[l-1] | (l>1 ? data[0]<<8 : 0);
uint16_t us;
if (input > 0x0ffff)
- return staticerr(ip, "hbytes ushort2h input >2^16");
+ return staticerr(ip, "hbytes ushort2h input >2^16",
+ "HBYTES VALUE OVERFLOW");
us= htons(input);
hbytes_array(result,(const Byte*)&us,2);
return posixerr(ip,errno,"read " URANDOM);
} else {
assert(feof(urandom));
- return staticerr(ip, URANDOM " gave eof!");
+ return staticerr(ip, URANDOM " gave eof!", 0);
}
}
int do_ulong_int2ul(ClientData cd, Tcl_Interp *ip, int v,
uint32_t *result) {
- if (v<0) return staticerr(ip,"cannot convert -ve integer to ulong");
+ if (v<0) return
+ staticerr(ip,"cannot convert -ve integer to ulong","ULONG VALUE NEGATIVE");
*result= v;
return TCL_OK;
}
int do_ulong_ul2int(ClientData cd, Tcl_Interp *ip,
uint32_t v, int *result) {
- if (v>INT_MAX) return staticerr(ip,"ulong too large to fit in an int");
+ if (v>INT_MAX) return
+ staticerr(ip,"ulong too large to fit in an int", "ULONG VALUE OVERFLOW");
*result= v;
return TCL_OK;
}
int do_ulong_shift(ClientData cd, Tcl_Interp *ip, int right,
uint32_t v, int bits, uint32_t *result) {
- if (bits > 32) return staticerr(ip,"shift out of range (32) bits");
+ if (bits < 0) { bits= -bits; right= !right; }
+ if (bits > 32) return
+ staticerr(ip,"shift out of range (32) bits", "ULONG BITCOUNT OVERRUN");
*result= (bits==32 ? 0 :
right ? v >> bits : v << bits);
return TCL_OK;
int *ok_io, Tcl_Obj *arg) {
int rc, v;
rc= pat_int(ip, arg, &v); if (rc) return rc;
- if (v<0) return staticerr(ip,"value for bitfield is -ve");
+ if (v<0) return
+ staticerr(ip,"value for bitfield is -ve", "ULONG VALUE NEGATIVE");
*value_io= v;
return TCL_OK;
}
static int bf_uint_read(Tcl_Interp *ip, uint32_t *value_io,
int *ok_io, Tcl_Obj *arg) {
- if (*value_io > INT_MAX)
- return staticerr(ip,"value from bitfield exceeds INT_MAX");
+ if (*value_io > INT_MAX) return
+ staticerr(ip,"value from bitfield exceeds INT_MAX","ULONG VALUE OVERFLOW");
return bf_var_read(ip,arg, ret_int(ip,*value_io));
}
while (--objc) {
rc= Tcl_GetIntFromObj(ip,*++objv,&sz); if (rc) return rc;
- if (!--objc) return staticerr(ip,"wrong # args: missing bitfield type");
+ if (!--objc) return staticerr(ip,"wrong # args: missing bitfield type",0);
- if (sz<0) return staticerr(ip,"bitfield size is -ve");
- if (sz>pos) return staticerr(ip,"total size of bitfields >32");
+ if (sz<0)
+ return staticerr(ip,"bitfield size is -ve", "ULONG BITCOUNT NEGATIVE");
+ if (sz>pos) return
+ staticerr(ip,"total size of bitfields >32", "ULONG BITCOUNT OVERRUN");
pos -= sz;
if (ftype->want_arg) {
if (!--objc)
- return staticerr(ip,"wrong # args: missing arg for bitfield");
+ return staticerr(ip,"wrong # args: missing arg for bitfield",0);
arg= *++objv;
} else {
arg= 0;
if (!*ok_r) return TCL_OK;
if (this_field & ~sz_mask)
- return staticerr(ip,"bitfield value has more bits than bitfield");
+ return staticerr(ip,"bitfield value has more bits than bitfield",
+ "ULONG VALUE OVERFLOW");
value &= ~this_mask;
value |= (this_field << pos);
}
- if (pos != 0)
- return staticerr(ip,"bitfield sizes add up to <32");
+ if (pos != 0) return
+ staticerr(ip,"bitfield sizes add up to <32","ULONG BITCOUNT UNDERRUN");
*value_io= value;
return TCL_OK;
int l;
l= hbytes_len(OBJ_HBYTES(o));
- if (l > 4) return staticerr(ip, "hbytes as ulong must be of length < 4");
+ if (l > 4) return
+ staticerr(ip,"hbytes as ulong with length >4","HBYTES LENGTH OVERRUN");
ul= 0;
memcpy((Byte*)&ul + 4 - l, hbytes_data(OBJ_HBYTES(o)), l);
ul= htonl(ul);
} else {
ul= strtoul(str,&ep,16);
}
- if (*ep || errno) return staticerr(ip, "bad unsigned long value");
+ if (*ep || errno) return staticerr(ip, "bad unsigned long value", 0);
}