Commit 3c62f456 authored by Jan Včelák's avatar Jan Včelák 🚀

[dnssec] signature encoding, proper signedness handling in Dss-Sig-Value

parent 75f9d935
......@@ -16,6 +16,7 @@
#include <stdbool.h>
#include "bignum.h"
#include "binary.h"
#include "error.h"
#include "sign/der.h"
......@@ -68,12 +69,12 @@ static int asn1_decode_size(wire_ctx_t *wire, size_t *size)
}
/*!
* Decode an integer object and retrieves a pointer to it.
* Decode an unsigned integer object.
*/
static int asn1_decode_integer(wire_ctx_t *wire, dnssec_binary_t *value)
static int asn1_decode_integer(wire_ctx_t *wire, dnssec_binary_t *_value)
{
assert(wire);
assert(value);
assert(_value);
if (!asn1_expect_type(wire, ASN1_TYPE_INTEGER)) {
return DNSSEC_MALFORMED_DATA;
......@@ -85,14 +86,21 @@ static int asn1_decode_integer(wire_ctx_t *wire, dnssec_binary_t *value)
return result;
}
if (size > wire_available(wire)) {
if (size == 0 || size > wire_available(wire)) {
return DNSSEC_MALFORMED_DATA;
}
value->size = size;
value->data = wire->position;
dnssec_binary_t value = { .data = wire->position, .size = size };
wire->position += size;
// skip leading zeroes (unless equal to zero)
while (value.size > 1 && value.data[0] == 0) {
value.data += 1;
value.size -= 1;
}
*_value = value;
return DNSSEC_EOK;
}
......@@ -109,16 +117,17 @@ static void asn1_write_header(wire_ctx_t *wire, uint8_t type, size_t length)
}
/*!
* Encode integer object.
* Encode unsigned integer object.
*/
static void asn1_write_integer(wire_ctx_t *wire, const dnssec_binary_t *integer)
static void asn1_write_integer(wire_ctx_t *wire, size_t integer_size,
const dnssec_binary_t *integer)
{
assert(wire);
assert(integer);
assert(integer->data);
asn1_write_header(wire, ASN1_TYPE_INTEGER, integer->size);
wire_write_binary(wire, integer);
asn1_write_header(wire, ASN1_TYPE_INTEGER, integer_size);
wire_write_bignum(wire, integer_size, integer);
}
/*!
......@@ -179,19 +188,22 @@ int dss_sig_value_decode(const dnssec_binary_t *der,
* Encode signature parameters from X.509 (EC)DSA signature.
*/
int dss_sig_value_encode(const dnssec_binary_t *r, const dnssec_binary_t *s,
dnssec_binary_t *der)
dnssec_binary_t *_der)
{
if (!r || !r->data || !s || !s->data || !der) {
if (!r || !r->data || !s || !s->data || !_der) {
return DNSSEC_EINVAL;
}
size_t r_size = bignum_size_s(r);
size_t s_size = bignum_size_s(s);
// check supported inputs range
if (r->size > ASN1_MAX_SIZE || s->size > ASN1_MAX_SIZE) {
if (r_size > ASN1_MAX_SIZE || s_size > ASN1_MAX_SIZE) {
return DNSSEC_NOT_IMPLEMENTED_ERROR;
}
size_t seq_size = 2 + r->size + 2 + s->size;
size_t seq_size = 2 + r_size + 2 + s_size;
if (seq_size > ASN1_MAX_SIZE) {
return DNSSEC_NOT_IMPLEMENTED_ERROR;
}
......@@ -199,20 +211,19 @@ int dss_sig_value_encode(const dnssec_binary_t *r, const dnssec_binary_t *s,
// encode result
size_t total_size = 2 + seq_size;
uint8_t *encoded = malloc(total_size);
if (!encoded) {
dnssec_binary_t der = { 0 };
if (dnssec_binary_alloc(&der, total_size)) {
return DNSSEC_ENOMEM;
}
wire_ctx_t wire = wire_init(encoded, total_size);
wire_ctx_t wire = wire_init_binary(&der);
asn1_write_header(&wire, ASN1_TYPE_SEQUENCE, seq_size);
asn1_write_integer(&wire, r);
asn1_write_integer(&wire, s);
asn1_write_integer(&wire, r_size, r);
asn1_write_integer(&wire, s_size, s);
assert(wire_available(&wire) == 0);
der->size = total_size;
der->data = encoded;
*_der = der;
return DNSSEC_EOK;
}
......@@ -25,6 +25,10 @@
* of the signature.
*
* This module provides decoding and encoding of this format.
*
* The 'r' and 's' values are treated as unsigned values: The leading zeroes
* are stripped on decoding; an extra leading zero is added on encoding in case
* the value starts with a set bit.
*/
/*!
......
......@@ -17,107 +17,186 @@
#include <tap/basic.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include "binary.h"
#include "error.h"
#include "sign/der.h"
/*!
* Check conversion of Dss-Sig-Value to parameters.
*/
void raw_to_params(void)
static int binary_eq(const dnssec_binary_t *a, const dnssec_binary_t *b)
{
const dnssec_binary_t raw = { .size = 103, .data = (uint8_t []) {
0x30,0x65,0x02,0x31,0x00,0xcd,0xe6,0xf6,0xf5,0x2e,
0x4b,0xd9,0xfe,0x32,0xf7,0x94,0x3d,0x60,0x5a,0x5f,
0x17,0x0f,0x2e,0xec,0xd2,0xc2,0x6d,0x79,0xba,0x85,
0xf0,0x57,0xf4,0x15,0x2d,0x04,0xbd,0xb8,0xc9,0x24,
0x15,0x9a,0x9b,0x74,0x91,0x75,0xb0,0x22,0x47,0x85,
0x19,0x45,0x58,0x02,0x30,0x5b,0xe2,0x9d,0x18,0x71,
0x5d,0xb3,0xd8,0x0b,0x5d,0xee,0x9c,0x38,0x79,0x46,
0x29,0x90,0x89,0xd5,0x21,0xb0,0x82,0x45,0x78,0x2e,
0xf0,0x68,0xa9,0xfa,0x76,0xaa,0xe2,0x36,0x47,0xcc,
0x3c,0x74,0x2d,0xfc,0x6d,0xa6,0x72,0x35,0x29,0xc7,
0x21,0xcf,0x5c
}};
const dnssec_binary_t expected_r = { .size = 49, .data = (uint8_t []) {
0x00,0xcd,0xe6,0xf6,0xf5,0x2e,0x4b,0xd9,0xfe,0x32,
0xf7,0x94,0x3d,0x60,0x5a,0x5f,0x17,0x0f,0x2e,0xec,
0xd2,0xc2,0x6d,0x79,0xba,0x85,0xf0,0x57,0xf4,0x15,
0x2d,0x04,0xbd,0xb8,0xc9,0x24,0x15,0x9a,0x9b,0x74,
0x91,0x75,0xb0,0x22,0x47,0x85,0x19,0x45,0x58
}};
const dnssec_binary_t expected_s = { .size = 48, .data = (uint8_t []) {
0x5b,0xe2,0x9d,0x18,0x71,0x5d,0xb3,0xd8,0x0b,0x5d,
0xee,0x9c,0x38,0x79,0x46,0x29,0x90,0x89,0xd5,0x21,
0xb0,0x82,0x45,0x78,0x2e,0xf0,0x68,0xa9,0xfa,0x76,
0xaa,0xe2,0x36,0x47,0xcc,0x3c,0x74,0x2d,0xfc,0x6d,
0xa6,0x72,0x35,0x29,0xc7,0x21,0xcf,0x5c
}};
dnssec_binary_t value_r = { 0 };
dnssec_binary_t value_s = { 0 };
int result = dss_sig_value_decode(&raw, &value_r, &value_s);
ok(result == DNSSEC_EOK, "dss_sig_value_decode() exit code");
ok(value_r.size == expected_r.size && value_r.data != NULL &&
memcmp(value_r.data, expected_r.data, expected_r.size) == 0,
"dss_sig_value_decode() correct r value");
ok(value_s.size == expected_s.size && value_s.data != NULL &&
memcmp(value_s.data, expected_s.data, expected_s.size) == 0,
"dss_sig_value_decode() correct s value");
return a && b &&
a->size == b->size &&
memcmp(a->data, b->data, a->size) == 0;
}
/*!
* Check conversion from parameters to Dss-Sig-Value.
*/
void params_to_raw(void)
{
const dnssec_binary_t value_r = { .size = 32, .data = (uint8_t []) {
0x2e,0x79,0xdd,0x3e,0xec,0x80,0x8c,0xd7,0x0c,0x22,
0x51,0x28,0xb3,0xcd,0x28,0x8e,0xc6,0x24,0xe1,0xfc,
0xd7,0x37,0xdb,0xc1,0x17,0xbb,0x88,0x63,0xec,0x1a,
0x3c,0x7c
}};
const dnssec_binary_t value_s = { .size = 33, .data = (uint8_t []) {
0x00,0x8c,0x40,0x58,0x99,0x53,0x43,0x5d,0xcb,0x21,
0xf0,0x81,0x6d,0xd3,0x02,0x67,0x85,0x8f,0x4a,0x34,
0x9c,0x2a,0x21,0x47,0xf3,0x76,0x48,0xdf,0xfe,0x52,
0x54,0xf9,0xa5,
}};
const dnssec_binary_t expected_raw = { .size = 71, .data = (uint8_t []) {
0x30,0x45,0x02,0x20,0x2e,0x79,0xdd,0x3e,0xec,0x80,
0x8c,0xd7,0x0c,0x22,0x51,0x28,0xb3,0xcd,0x28,0x8e,
0xc6,0x24,0xe1,0xfc,0xd7,0x37,0xdb,0xc1,0x17,0xbb,
0x88,0x63,0xec,0x1a,0x3c,0x7c,0x02,0x21,0x00,0x8c,
0x40,0x58,0x99,0x53,0x43,0x5d,0xcb,0x21,0xf0,0x81,
0x6d,0xd3,0x02,0x67,0x85,0x8f,0x4a,0x34,0x9c,0x2a,
0x21,0x47,0xf3,0x76,0x48,0xdf,0xfe,0x52,0x54,0xf9,
0xa5,
}};
dnssec_binary_t raw = { 0 };
int result = dss_sig_value_encode(&value_r, &value_s, &raw);
ok(result == DNSSEC_EOK, "dss_sig_value_encode() exit code");
ok(raw.size == expected_raw.size && raw.data != NULL &&
memcmp(raw.data, expected_raw.data, expected_raw.size) == 0,
"dss_sig_value_encode() correct der value");
dnssec_binary_free(&raw);
}
#define DECODE_OK(der, r, s, message) \
dnssec_binary_t __der = { .data = der, .size = sizeof(der) }; \
dnssec_binary_t __r = { .data = r, .size = sizeof(r) }; \
dnssec_binary_t __s = { .data = s, .size = sizeof(s) }; \
dnssec_binary_t __out_s = { 0 }; \
dnssec_binary_t __out_r = { 0 }; \
int _result = dss_sig_value_decode(&__der, &__out_r, &__out_s); \
ok(_result == DNSSEC_EOK && \
binary_eq(&__r, &__out_r) && \
binary_eq(&__s, &__out_s), \
"decode ok, " message)
#define DECODE_FAIL(der, message) \
dnssec_binary_t __der = { .data = der, .size = sizeof(der) }; \
dnssec_binary_t __out_r = { 0 }; \
dnssec_binary_t __out_s = { 0 }; \
int _result = dss_sig_value_decode(&__der, &__out_r, &__out_s); \
ok(_result != DNSSEC_EOK, \
"decode fail, " message)
#define ENCODE_OK(r, s, der, message) \
dnssec_binary_t __r = { .data = r, .size = sizeof(r) }; \
dnssec_binary_t __s = { .data = s, .size = sizeof(s) }; \
dnssec_binary_t __der = { .data = der, .size = sizeof(der) }; \
dnssec_binary_t __out_der = { 0 }; \
int _result = dss_sig_value_encode(&__r, &__s, &__out_der); \
ok(_result == DNSSEC_EOK && \
binary_eq(&__der, &__out_der), \
"encode ok, " message); \
dnssec_binary_free(&__out_der)
#define ENCODE_FAIL(r, s, message) \
dnssec_binary_t __r = { .data = r, .size = sizeof(r) }; \
dnssec_binary_t __s = { .data = s, .size = sizeof(s) }; \
dnssec_binary_t __out_der = { 0 }; \
int _result = dss_sig_value_encode(&__r, &__s, &__out_der); \
ok(_result != DNSSEC_EOK, \
"encode fail, " message); \
dnssec_binary_free(&__out_der)
#define ONE_64_TIMES \
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, \
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, \
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, \
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, \
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, \
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, \
0x01,0x01,0x01,0x01
#define ONE_128_TIMES \
ONE_64_TIMES, ONE_64_TIMES
int main(void)
{
plan_lazy();
raw_to_params();
params_to_raw();
{
uint8_t der[] = { 0x30,0x08, 0x02,0x02,0x1a,0x2b, 0x02,0x02,0x3c,0x4d };
uint8_t r[] = { 0x1a, 0x2b };
uint8_t s[] = { 0x3c, 0x4d };
DECODE_OK(der, r, s, "simple without MSB");
}
{
uint8_t der[] = { 0x30,0x08, 0x02,0x02,0xff,0xff, 0x02,0x02,0x80,0x00 };
uint8_t r[] = { 0xff, 0xff };
uint8_t s[] = { 0x80, 0x00 };
DECODE_OK(der, r, s, "simple with MSB");
}
{
uint8_t der[] = { 0x30,0x09, 0x02,0x04,0x00,0x00,0x00,0xfa, 0x02,0x01,0x07 };
uint8_t r[] = { 0xfa };
uint8_t s[] = { 0x07 };
DECODE_OK(der, r, s, "leading zeros");
}
{
uint8_t der[] = { 0x30,0x07, 0x02,0x01,0x00, 0x02,0x02,0x00,0x00 };
uint8_t r[] = { 0x00 };
uint8_t s[] = { 0x00 };
DECODE_OK(der, r, s, "zero values" );
}
{
uint8_t der[] = { };
DECODE_FAIL(der, "empty input");
}
{
uint8_t der[] = { 0x30,0x04, 0x02,0x01,0x01 };
DECODE_FAIL(der, "partial sequence");
}
{
uint8_t der[] = { 0x30,0x06, 0x02,0x01,0x01, 0x02,0x02,0x01 };
DECODE_FAIL(der, "partial integer");
}
{
uint8_t der[] = { 0x30,0x00 };
DECODE_FAIL(der, "zero-length sequence");
}
{
uint8_t der[] = { 0x30,0x05, 0x02,0x01,0xff, 0x02,0x00 };
DECODE_FAIL(der, "zero-length integer");
}
{
uint8_t der[] = { 0x30,0x84, 0x02,0x40,ONE_64_TIMES, 0x02,0x40,ONE_64_TIMES };
DECODE_FAIL(der, "unsupported size");
}
{
uint8_t r[] = { 0x01, };
uint8_t s[] = { 0x02,0x03 };
uint8_t der[] = { 0x30,0x07, 0x02,0x01,0x01, 0x02,0x02,0x02,0x03 };
ENCODE_OK(r, s, der, "simple");
}
{
uint8_t r[] = { 0x00,0x01, };
uint8_t s[] = { 0x00,0x00,0x02,0x03 };
uint8_t der[] = { 0x30,0x07, 0x02,0x01,0x01, 0x02,0x02,0x02,0x03 };
ENCODE_OK(r, s, der, "unnecessary leading zeros");
}
{
uint8_t r[] = { 0x00,0x8f };
uint8_t s[] = { 0x00,0x00,0xff };
uint8_t der[] = { 0x30,0x08, 0x02,0x02,0x00,0x8f, 0x02,0x02,0x00,0xff };
ENCODE_OK(r, s, der, "required zero not removed");
}
{
uint8_t r[] = { 0x8c };
uint8_t s[] = { 0xff,0xee };
uint8_t der[] = { 0x30,0x09, 0x02,0x02,0x00,0x8c, 0x02,0x03,0x00,0xff,0xee };
ENCODE_OK(r, s, der, "implicitly added zero");
}
{
uint8_t r[] = { 0x00 };
uint8_t s[] = { 0x00,0x00 };
uint8_t der[] = { 0x30,0x06, 0x02,0x01,0x00, 0x02,0x01,0x00 };
ENCODE_OK(r, s, der, "zero");
}
{
uint8_t r[] = { 0x01 };
uint8_t s[] = { };
uint8_t der[] = { 0x30,0x06, 0x02,0x01,0x01, 0x02,0x01,0x00 };
ENCODE_OK(r, s, der, "zero-length input");
}
{
uint8_t r[] = { ONE_128_TIMES };
uint8_t s[] = { 0x01 };
ENCODE_FAIL(r, s, "input too long");
}
{
uint8_t r[] = { ONE_64_TIMES };
uint8_t s[] = { ONE_64_TIMES };
ENCODE_FAIL(r, s, "result too long");
}
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment