Closed mabuchner closed 2 years ago
The changes in dsa_test.c
aren't helping. It didn't store a key in the old format.
I've written a function to import a DSA key in the old format
static int read_old_header(const unsigned char* in, const unsigned char* end, int* bytesRead)
{
const int PACKET_SECT_DSA_OLD = 3;
const int PACKET_SUB_SIGNED = 2;
*bytesRead = 0;
const int headerSize = 4;
if (in + headerSize > end)
{
return CRYPT_INVALID_PACKET;
}
const unsigned long version = in[1] << 8 | in[0];
if (version >= 0x0103)
{
// libtomcrypt v1.03 uses a different format
return CRYPT_INVALID_PACKET;
}
*bytesRead += 2;
const int section = in[2];
if (section != PACKET_SECT_DSA_OLD)
{
return CRYPT_INVALID_PACKET;
}
*bytesRead += 1;
const int subsection = in[3];
if (subsection != PACKET_SUB_SIGNED)
{
return CRYPT_INVALID_PACKET;
}
*bytesRead += 1;
return CRYPT_OK;
}
static int
read_old_big_num(const unsigned char* sig, const unsigned char* end, void* num, int* bytesRead)
{
*bytesRead = 0;
const int numHeaderSize = 2;
if (sig + numHeaderSize > end)
{
return CRYPT_INVALID_PACKET;
}
const int numLength = (sig[0] << 8) | sig[1];
*bytesRead += numHeaderSize;
sig += numHeaderSize;
if (sig + numLength > end)
{
return CRYPT_INVALID_PACKET;
}
const int err = mp_read_unsigned_bin(num, (unsigned char*)sig, numLength);
// Unfortunately, the const cast is necessary, because the input pointer
// is declared as non-const. The libtommath implementation of this
// function then uses a const pointer.
if (err != CRYPT_OK)
{
return err;
}
*bytesRead += numLength;
return CRYPT_OK;
}
int dsa_verify_hash_old(const unsigned char* sig, unsigned long siglen,
const unsigned char *hash, unsigned long hashlen,
int* stat, dsa_key* key)
{
*stat = 0;
const unsigned char* end = sig + siglen;
int headerSize = 0;
const int readHeaderResult = read_old_header(sig, end, &headerSize);
if (readHeaderResult != CRYPT_OK)
{
return readHeaderResult;
}
sig += headerSize;
void* r = NULL;
void* s = NULL;
int initMultiResult = CRYPT_ERROR;
if ((initMultiResult = mp_init_multi(&r, &s, NULL)) != CRYPT_OK)
{
return initMultiResult;
}
int bytesRead = 0;
if (read_old_big_num(sig, end, r, &bytesRead) != CRYPT_OK)
{
mp_clear_multi(r, s, NULL);
return CRYPT_INVALID_PACKET;
}
sig += bytesRead;
if (read_old_big_num(sig, end, s, &bytesRead) != CRYPT_OK)
{
mp_clear_multi(r, s, NULL);
return CRYPT_INVALID_PACKET;
}
if (dsa_verify_hash_raw(r, s, hash, hashlen, stat, key) != CRYPT_OK)
{
mp_clear_multi(r, s, NULL);
return CRYPT_INVALID_PACKET;
}
mp_clear_multi(r, s, NULL);
return CRYPT_OK;
}
The format of the signatures also has changed. Here is a function to verify a signed hash with the old signature format.
static int read_old_header(const unsigned char* in, const unsigned char* end, int* bytesRead)
{
const int PACKET_SECT_DSA_OLD = 3;
const int PACKET_SUB_SIGNED = 2;
*bytesRead = 0;
const int headerSize = 4;
if (in + headerSize > end)
{
return CRYPT_INVALID_PACKET;
}
const unsigned long version = in[1] << 8 | in[0];
if (version >= 0x0103)
{
// libtomcrypt v1.03 uses a different format
return CRYPT_INVALID_PACKET;
}
*bytesRead += 2;
const int section = in[2];
if (section != PACKET_SECT_DSA_OLD)
{
return CRYPT_INVALID_PACKET;
}
*bytesRead += 1;
const int subsection = in[3];
if (subsection != PACKET_SUB_SIGNED)
{
return CRYPT_INVALID_PACKET;
}
*bytesRead += 1;
return CRYPT_OK;
}
static int
read_old_big_num(const unsigned char* sig, const unsigned char* end, void* num, int* bytesRead)
{
*bytesRead = 0;
const int numHeaderSize = 2;
if (sig + numHeaderSize > end)
{
return CRYPT_INVALID_PACKET;
}
const int numLength = (sig[0] << 8) | sig[1];
*bytesRead += numHeaderSize;
sig += numHeaderSize;
if (sig + numLength > end)
{
return CRYPT_INVALID_PACKET;
}
const int err = mp_read_unsigned_bin(num, (unsigned char*)sig, numLength);
// Unfortunately, the const cast is necessary, because the input pointer
// is declared as non-const. The libtommath implementation of this
// function then uses a const pointer.
if (err != CRYPT_OK)
{
return err;
}
*bytesRead += numLength;
return CRYPT_OK;
}
int dsa_verify_hash_old(const unsigned char* sig, unsigned long siglen,
const unsigned char *hash, unsigned long hashlen,
int* stat, dsa_key* key)
{
*stat = 0;
const unsigned char* end = sig + siglen;
int headerSize = 0;
const int readHeaderResult = read_old_header(sig, end, &headerSize);
if (readHeaderResult != CRYPT_OK)
{
return readHeaderResult;
}
sig += headerSize;
void* r = NULL;
void* s = NULL;
int initMultiResult = CRYPT_ERROR;
if ((initMultiResult = mp_init_multi(&r, &s, NULL)) != CRYPT_OK)
{
return initMultiResult;
}
int bytesRead = 0;
if (read_old_big_num(sig, end, r, &bytesRead) != CRYPT_OK)
{
mp_clear_multi(r, s, NULL);
return CRYPT_INVALID_PACKET;
}
sig += bytesRead;
if (read_old_big_num(sig, end, s, &bytesRead) != CRYPT_OK)
{
mp_clear_multi(r, s, NULL);
return CRYPT_INVALID_PACKET;
}
if (dsa_verify_hash_raw(r, s, hash, hashlen, stat, key) != CRYPT_OK)
{
mp_clear_multi(r, s, NULL);
return CRYPT_INVALID_PACKET;
}
mp_clear_multi(r, s, NULL);
return CRYPT_OK;
}
Now fighting with the changes from #133.
A dirty workaround is to add
key->qord = hashlen;
in front of dsa_verify_hash_raw
in dsa_verify_hash_old
.
I will close this issue, as my solution from above seems to work.
I'm trying to update our code base from libtomcrypt v0.93 to v1.18.2. After some struggling, I've finally managed to compile libtommath and libtommath on all of our supported platforms.
Unfortunately, now our tests are failing with "Invalid input packet" errors. It seems like the key format of the
dsa_import
function (and probably also of thedsa_export
function) was changed in v1.03 (see here). The first byte of our public key is0x93
, but the new code seems to expect0x30
or0x31
.Is there some way to convert keys from the old format to the new format?