Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wycheproof failing ECC tests #446

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/headers/tomcrypt_pk.h
Original file line number Diff line number Diff line change
Expand Up @@ -596,9 +596,17 @@ enum ltc_der_seq {
LTC_DER_SEQ_RELAXED = LTC_DER_SEQ_ZERO,
LTC_DER_SEQ_STRICT = 0x2u,

/** Bit2 - [0]=Relaxed Length Check
* [1]=Strict Length Check */
LTC_DER_SEQ_LEN_RELAXED = LTC_DER_SEQ_ZERO,
LTC_DER_SEQ_LEN_STRICT = 0x4u,

/** Alternative naming */
LTC_DER_SEQ_SET = LTC_DER_SEQ_UNORDERED,
LTC_DER_SEQ_SEQUENCE = LTC_DER_SEQ_ORDERED,

LTC_DER_SEQ_ALL_STRICT = LTC_DER_SEQ_STRICT | LTC_DER_SEQ_LEN_STRICT,

};

int der_decode_sequence_ex(const unsigned char *in, unsigned long inlen,
Expand Down
3 changes: 2 additions & 1 deletion src/headers/tomcrypt_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,8 @@ int der_decode_asn1_identifier(const unsigned char *in, unsigned long *inlen, lt
int der_length_asn1_identifier(const ltc_asn1_list *id, unsigned long *idlen);

int der_encode_asn1_length(unsigned long len, unsigned char* out, unsigned long* outlen);
int der_decode_asn1_length(const unsigned char *in, unsigned long *inlen, unsigned long *outlen);
int der_decode_asn1_length_ex(const unsigned char *in, unsigned long *inlen, unsigned long *outlen, unsigned int flags);
#define der_decode_asn1_length(i, il, ol) der_decode_asn1_length_ex(i, il, ol, 0)
int der_length_asn1_length(unsigned long len, unsigned long *outlen);

int der_length_sequence_ex(const ltc_asn1_list *list, unsigned long inlen,
Expand Down
6 changes: 4 additions & 2 deletions src/pk/asn1/der/custom_type/der_decode_custom_type.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ int der_decode_custom_type_ex(const unsigned char *in, unsigned long inlen,
int err, seq_err, i, ordered;
ltc_asn1_type type;
ltc_asn1_list ident;
unsigned int f;
unsigned long size, x, y, z, blksize;
unsigned char* in_new = NULL;
void *data;
Expand All @@ -63,7 +64,8 @@ int der_decode_custom_type_ex(const unsigned char *in, unsigned long inlen,
LTC_ARGCHK(list != NULL);

/* sequence type? We allow 0x30 SEQUENCE and 0x31 SET since fundamentally they're the same structure */
if (in[x] != 0x30 && in[x] != 0x31) {
f = flags & ~(LTC_DER_SEQ_ALL_STRICT);
if (((f == LTC_DER_SEQ_SEQUENCE) && (in[x] != 0x30)) || (((f == LTC_DER_SEQ_SET) && (in[x] != 0x31)))) {
return CRYPT_INVALID_PACKET;
}
++x;
Expand Down Expand Up @@ -116,7 +118,7 @@ int der_decode_custom_type_ex(const unsigned char *in, unsigned long inlen,
} else {

y = inlen - x;
if ((err = der_decode_asn1_length(&in[x], &y, &blksize)) != CRYPT_OK) {
if ((err = der_decode_asn1_length_ex(&in[x], &y, &blksize, flags)) != CRYPT_OK) {
goto LBL_ERR;
}
x += y;
Expand Down
9 changes: 8 additions & 1 deletion src/pk/asn1/der/general/der_decode_asn1_length.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
@param outlen [out] The decoded ASN.1 length
@return CRYPT_OK if successful
*/
int der_decode_asn1_length(const unsigned char *in, unsigned long *inlen, unsigned long *outlen)
int der_decode_asn1_length_ex(const unsigned char *in, unsigned long *inlen, unsigned long *outlen, unsigned int flags)
{
unsigned long real_len, decoded_len, offset, i;

Expand All @@ -42,10 +42,17 @@ int der_decode_asn1_length(const unsigned char *in, unsigned long *inlen, unsign
if (real_len > (*inlen - 1)) {
return CRYPT_BUFFER_OVERFLOW;
}
flags &= LTC_DER_SEQ_LEN_STRICT;
decoded_len = 0;
offset = 1 + real_len;
for (i = 0; i < real_len; i++) {
decoded_len = (decoded_len << 8) | in[1 + i];
if ((flags == LTC_DER_SEQ_LEN_STRICT) && (decoded_len == 0)) {
return CRYPT_PK_ASN1_ERROR;
}
}
if ((flags == LTC_DER_SEQ_LEN_STRICT) && (real_len == 1) && (decoded_len < 128)) {
return CRYPT_PK_ASN1_ERROR;
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/pk/ecc/ecc_verify_hash.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ int ecc_verify_hash_ex(const unsigned char *sig, unsigned long siglen,

if (sigformat == LTC_ECCSIG_ANSIX962) {
/* ANSI X9.62 format - ASN.1 encoded SEQUENCE{ INTEGER(r), INTEGER(s) } */
if ((err = der_decode_sequence_multi_ex(sig, siglen, LTC_DER_SEQ_SEQUENCE | LTC_DER_SEQ_STRICT,
if ((err = der_decode_sequence_multi_ex(sig, siglen, LTC_DER_SEQ_SEQUENCE | LTC_DER_SEQ_ALL_STRICT,
LTC_ASN1_INTEGER, 1UL, r,
LTC_ASN1_INTEGER, 1UL, s,
LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) { goto error; }
Expand Down
172 changes: 172 additions & 0 deletions tests/ecc_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,177 @@ static int s_ecc_issue443_447(void)
return CRYPT_OK;
}

/* https://github.com/libtom/libtomcrypt/issues/446 */
static int s_ecc_issue446(void)
{
const ltc_ecc_curve* cu;
ecc_key key1, key2, key3, key4;
int err, stat = 0;
unsigned char hash[64];
unsigned long hashlen;
const unsigned char msg1[] = { 0x31,0x32,0x33,0x34,0x30,0x30 };
const unsigned char msg2[] = { 0x36,0x39,0x38,0x31,0x39 };
const unsigned char msg3[] = { 0x4d,0x73,0x67 };
const unsigned char msg4[] = { 0x54,0x65,0x73,0x74 };
const unsigned char pub1[] = {
0x04, /* secp256r1 */
0x29,0x27,0xb1,0x05,0x12,0xba,0xe3,0xed,0xdc,0xfe,0x46,0x78,0x28,0x12,0x8b,0xad,
0x29,0x03,0x26,0x99,0x19,0xf7,0x08,0x60,0x69,0xc8,0xc4,0xdf,0x6c,0x73,0x28,0x38,
0xc7,0x78,0x79,0x64,0xea,0xac,0x00,0xe5,0x92,0x1f,0xb1,0x49,0x8a,0x60,0xf4,0x60,
0x67,0x66,0xb3,0xd9,0x68,0x50,0x01,0x55,0x8d,0x1a,0x97,0x4e,0x73,0x41,0x51,0x3e
};
const unsigned char pub2[] = {
0x04, /* secp224r1 */
0x53,0x88,0x35,0x38,0xd8,0x66,0x09,0x21,0x7a,0x4d,0x9c,0x27,0x99,0x2e,
0x2b,0xd7,0x04,0xa4,0xbb,0x12,0xfb,0x91,0x25,0x3c,0xd4,0xf4,0x96,0xfa,
0x00,0xb3,0x2f,0x3a,0x2d,0x15,0x3a,0x52,0xbb,0x57,0x76,0x50,0xcd,0xf1,
0xb7,0x3a,0x34,0x05,0x35,0xc7,0xe7,0x3d,0xeb,0x59,0x9a,0xa9,0x50,0x88
};
const unsigned char pub3[] = {
0x04, /* brainpoolP256r1 */
0x30,0x29,0x1b,0xca,0x4e,0xb9,0x3c,0x41,0x99,0x1d,0xae,0xc0,0xfd,0x2e,0x87,0xc2,
0x77,0x8d,0x95,0x8d,0x9a,0x8e,0x2f,0xa4,0xe6,0xd3,0x83,0x5d,0x48,0x5b,0xc2,0x3e,
0x42,0x17,0xf6,0x84,0xcf,0xdd,0x83,0x6d,0x7c,0xf6,0x09,0x9a,0x34,0xc6,0x82,0x61,
0xe5,0xa0,0x94,0xad,0xb5,0xb3,0xe4,0xa9,0x26,0x2f,0xf5,0x95,0x7c,0x1b,0x1b,0xa8
};
const unsigned char pub4[] = {
0x04, /* brainpoolP256t1 */
0x44,0x24,0xf0,0x9e,0x4f,0x86,0x92,0x31,0xe4,0x7b,0x1e,0x34,0x26,0xec,0x26,0x9e,
0x5b,0xef,0x19,0xec,0x64,0xcc,0x96,0xda,0x5b,0x2e,0xfd,0xd2,0x11,0x6b,0x83,0xf0,
0x7a,0x86,0x3d,0x25,0x74,0x3b,0xb2,0x60,0xa6,0x38,0xde,0x64,0x97,0x96,0xc6,0x76,
0xe1,0x38,0x05,0x86,0x5c,0x8b,0xb9,0xda,0xc3,0x8e,0x16,0xfa,0xe5,0x4b,0x0c,0xef
};
/* msg1+pub1+sig1 test vector is from wycheproof/ecdsa_test VALID */
const unsigned char sig1[] = {
0x30,0x45,0x02,0x20,0x2b,0xa3,0xa8,0xbe,0x6b,0x94,0xd5,0xec,0x80,0xa6,0xd9,0xd1,0x19,0x0a,
0x43,0x6e,0xff,0xe5,0x0d,0x85,0xa1,0xee,0xe8,0x59,0xb8,0xcc,0x6a,0xf9,0xbd,0x5c,0x2e,0x18,
0x02,0x21,0x00,0xb3,0x29,0xf4,0x79,0xa2,0xbb,0xd0,0xa5,0xc3,0x84,0xee,0x14,0x93,0xb1,0xf5,
0x18,0x6a,0x87,0x13,0x9c,0xac,0x5d,0xf4,0x08,0x7c,0x13,0x4b,0x49,0x15,0x68,0x47,0xdb
};
/* msg1+pub1+sig2 test vector is from wycheproof/ecdsa_test INVALID (changing tag value of sequence) */
const unsigned char sig2[] = {
0x31,0x45,0x02,0x20,0x2b,0xa3,0xa8,0xbe,0x6b,0x94,0xd5,0xec,0x80,0xa6,0xd9,0xd1,0x19,0x0a,
0x43,0x6e,0xff,0xe5,0x0d,0x85,0xa1,0xee,0xe8,0x59,0xb8,0xcc,0x6a,0xf9,0xbd,0x5c,0x2e,0x18,
0x02,0x21,0x00,0xb3,0x29,0xf4,0x79,0xa2,0xbb,0xd0,0xa5,0xc3,0x84,0xee,0x14,0x93,0xb1,0xf5,
0x18,0x6a,0x87,0x13,0x9c,0xac,0x5d,0xf4,0x08,0x7c,0x13,0x4b,0x49,0x15,0x68,0x47,0xdb
};
/* msg2+pub1+sig3 test vector is from wycheproof/ecdsa_test VALID (Edge case for Shamir multiplication) */
const unsigned char sig3[] = {
0x30,0x44,0x02,0x20,0x64,0xa1,0xaa,0xb5,0x00,0x0d,0x0e,0x80,0x4f,0x3e,0x2f,0xc0,0x2b,0xde,
0xe9,0xbe,0x8f,0xf3,0x12,0x33,0x4e,0x2b,0xa1,0x6d,0x11,0x54,0x7c,0x97,0x71,0x1c,0x89,0x8e,
0x02,0x20,0x6a,0xf0,0x15,0x97,0x1c,0xc3,0x0b,0xe6,0xd1,0xa2,0x06,0xd4,0xe0,0x13,0xe0,0x99,
0x77,0x72,0xa2,0xf9,0x1d,0x73,0x28,0x6f,0xfd,0x68,0x3b,0x9b,0xb2,0xcf,0x4f,0x1b
};
/* msg1+pub1+sig4 test vector is from wycheproof/ecdsa_test INVALID (long form encoding of length) */
const unsigned char sig4[] = {
0x30,0x81,0x45,0x02,0x20,0x2b,0xa3,0xa8,0xbe,0x6b,0x94,0xd5,0xec,0x80,0xa6,0xd9,0xd1,0x19,
0x0a,0x43,0x6e,0xff,0xe5,0x0d,0x85,0xa1,0xee,0xe8,0x59,0xb8,0xcc,0x6a,0xf9,0xbd,0x5c,0x2e,
0x18,0x02,0x21,0x00,0xb3,0x29,0xf4,0x79,0xa2,0xbb,0xd0,0xa5,0xc3,0x84,0xee,0x14,0x93,0xb1,
0xf5,0x18,0x6a,0x87,0x13,0x9c,0xac,0x5d,0xf4,0x08,0x7c,0x13,0x4b,0x49,0x15,0x68,0x47,0xdb
};
/* msg1+pub1+sig5 test vector is from wycheproof/ecdsa_test INVALID (length contains leading 0) */
sjaeckel marked this conversation as resolved.
Show resolved Hide resolved
const unsigned char sig5[] = {
0x30,0x82,0x00,0x45,0x02,0x20,0x2b,0xa3,0xa8,0xbe,0x6b,0x94,0xd5,0xec,0x80,0xa6,0xd9,0xd1,
0x19,0x0a,0x43,0x6e,0xff,0xe5,0x0d,0x85,0xa1,0xee,0xe8,0x59,0xb8,0xcc,0x6a,0xf9,0xbd,0x5c,
0x2e,0x18,0x02,0x21,0x00,0xb3,0x29,0xf4,0x79,0xa2,0xbb,0xd0,0xa5,0xc3,0x84,0xee,0x14,0x93,
0xb1,0xf5,0x18,0x6a,0x87,0x13,0x9c,0xac,0x5d,0xf4,0x08,0x7c,0x13,0x4b,0x49,0x15,0x68,0x47,0xdb
};
/* msg3+pub2+sig6 test vector is from wycheproof/ecdsa_test VALID (extreme value for k and edgecase s) */
const unsigned char sig6[] = {
0x30,0x3c,0x02,0x1c,0x70,0x6a,0x46,0xdc,0x76,0xdc,0xb7,0x67,0x98,0xe6,0x0e,0x6d,0x89,0x47,0x47,0x88,0xd1,
0x6d,0xc1,0x80,0x32,0xd2,0x68,0xfd,0x1a,0x70,0x4f,0xa6,0x02,0x1c,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
0x55,0x55,0x55,0x55,0x55,0x55,0x07,0x8b,0xa0,0x3d,0xa5,0x6a,0x06,0x9f,0x0d,0xc1,0xc9,0x74,0x0e,0x14
};
/* msg4+pub3+sig7 test vector is from wycheproof/ecdsa_test VALID (extreme value for k) */
const unsigned char sig7[] = {
0x30,0x44,0x02,0x20,0x74,0x3c,0xf1,0xb8,0xb5,0xcd,0x4f,0x2e,0xb5,0x5f,0x8a,0xa3,0x69,0x59,
0x3a,0xc4,0x36,0xef,0x04,0x41,0x66,0x69,0x9e,0x37,0xd5,0x1a,0x14,0xc2,0xce,0x13,0xea,0x0e,
0x02,0x20,0x77,0x47,0x2d,0x9a,0x28,0xb4,0xec,0xe7,0x1c,0xf4,0x13,0xa6,0x8e,0xac,0x0e,0xb4,
0x23,0xa1,0x6f,0xb4,0x62,0xb1,0xf4,0x87,0x06,0xfe,0xd4,0x8c,0xa4,0x37,0xbd,0x2d
};
/* msg4+pub4+sig8 test vector is from wycheproof/ecdsa_test VALID (extreme value for k and s^-1) */
const unsigned char sig8[] = {
0x30,0x45,0x02,0x21,0x00,0x83,0x38,0x42,0x7c,0x7c,0xf4,0xd1,0x1c,0xb9,0x81,0xd9,0xb1,0x87,
0x93,0xe3,0x77,0x9c,0x49,0x4c,0x50,0x2c,0x75,0xbd,0x73,0x9e,0x57,0x8d,0xe2,0xa7,0x00,0x57,
0x8d,0x02,0x20,0x30,0x90,0xf4,0x87,0xe5,0x1f,0x9e,0x35,0xc8,0xaf,0x70,0xbb,0x9a,0xb7,0xdf,
0x45,0x03,0x7e,0x23,0x0a,0x33,0xd2,0xc1,0xfd,0x96,0xe4,0x04,0x25,0x4f,0xcb,0x86,0x79
};

DO(ecc_find_curve("secp256r1", &cu));
DO(ecc_set_curve(cu, &key1));
DO(ecc_set_key(pub1, sizeof(pub1), PK_PUBLIC, &key1));

DO(ecc_find_curve("secp224r1", &cu));
DO(ecc_set_curve(cu, &key2));
DO(ecc_set_key(pub2, sizeof(pub2), PK_PUBLIC, &key2));

DO(ecc_find_curve("brainpoolP256r1", &cu));
DO(ecc_set_curve(cu, &key3));
DO(ecc_set_key(pub3, sizeof(pub3), PK_PUBLIC, &key3));

DO(ecc_find_curve("brainpoolP256t1", &cu));
DO(ecc_set_curve(cu, &key4));
DO(ecc_set_key(pub4, sizeof(pub4), PK_PUBLIC, &key4));

hashlen = sizeof(hash);
DO(hash_memory(find_hash("sha256"), msg1, sizeof(msg1), hash, &hashlen));
DO(ecc_verify_hash(sig1, sizeof(sig1), hash, hashlen, &stat, &key1));
if (stat != 1) return CRYPT_FAIL_TESTVECTOR; /* expected result: VALID */

err = ecc_verify_hash(sig2, sizeof(sig2), hash, hashlen, &stat, &key1);
if (err == CRYPT_OK && stat == 1) {
fprintf(stderr, "XXX-TODO should fail - wycheproof / changing tag value of sequence\n");
/* return CRYPT_FAIL_TESTVECTOR; / * expected result: INVALID */
}

err = ecc_verify_hash(sig4, sizeof(sig4), hash, hashlen, &stat, &key1);
if (err == CRYPT_OK && stat == 1) {
fprintf(stderr, "XXX-TODO should fail - wycheproof / long form encoding of length\n");
/* return CRYPT_FAIL_TESTVECTOR; / * expected result: INVALID */
}

err = ecc_verify_hash(sig5, sizeof(sig5), hash, hashlen, &stat, &key1);
if (err == CRYPT_OK && stat == 1) {
fprintf(stderr, "XXX-TODO should fail - wycheproof / length contains leading 0\n");
/* return CRYPT_FAIL_TESTVECTOR; / * expected result: INVALID */
}

hashlen = sizeof(hash);
DO(hash_memory(find_hash("sha256"), msg2, sizeof(msg2), hash, &hashlen));
DO(ecc_verify_hash(sig3, sizeof(sig3), hash, hashlen, &stat, &key1));
if (stat != 1) {
fprintf(stderr, "XXX-TODO should be valid - wycheproof / Edge case for Shamir multiplication\n");
/* return CRYPT_FAIL_TESTVECTOR; / * expected result: VALID */
}

hashlen = sizeof(hash);
DO(hash_memory(find_hash("sha224"), msg3, sizeof(msg3), hash, &hashlen));
DO(ecc_verify_hash(sig6, sizeof(sig6), hash, hashlen, &stat, &key2));
if (stat != 1) {
fprintf(stderr, "XXX-TODO should be valid - wycheproof / extreme value for k and edgecase s\n");
/* return CRYPT_FAIL_TESTVECTOR; / * expected result: VALID */
}

hashlen = sizeof(hash);
DO(hash_memory(find_hash("sha256"), msg4, sizeof(msg4), hash, &hashlen));
DO(ecc_verify_hash(sig7, sizeof(sig7), hash, hashlen, &stat, &key3));
if (stat != 1) {
fprintf(stderr, "XXX-TODO should be valid - wycheproof / extreme value for k\n");
/* return CRYPT_FAIL_TESTVECTOR; / * expected result: VALID */
}
DO(ecc_verify_hash(sig8, sizeof(sig8), hash, hashlen, &stat, &key4));
if (stat != 1) {
fprintf(stderr, "XXX-TODO should be valid - wycheproof / extreme value for k and s^-1\n");
/* return CRYPT_FAIL_TESTVECTOR; / * expected result: VALID */
}

ecc_free(&key1);
ecc_free(&key2);
ecc_free(&key3);
ecc_free(&key4);
return CRYPT_OK;
}

static int s_ecc_test_mp(void)
{
void *a, *modulus, *order;
Expand Down Expand Up @@ -1591,6 +1762,7 @@ int ecc_test(void)
DO(s_ecc_test_mp());
DO(s_ecc_issue108());
DO(s_ecc_issue443_447());
DO(s_ecc_issue446());
#ifdef LTC_ECC_SHAMIR
DO(s_ecc_test_shamir());
DO(s_ecc_test_recovery());
Expand Down