1 /*  Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
2 
3     This program is free software: you can redistribute it and/or modify
4     it under the terms of the GNU General Public License as published by
5     the Free Software Foundation, either version 3 of the License, or
6     (at your option) any later version.
7 
8     This program is distributed in the hope that it will be useful,
9     but WITHOUT ANY WARRANTY; without even the implied warranty of
10     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11     GNU General Public License for more details.
12 
13     You should have received a copy of the GNU General Public License
14     along with this program.  If not, see <https://www.gnu.org/licenses/>.
15  */
16 
17 #include <stdbool.h>
18 
19 #include "libdnssec/shared/bignum.h"
20 #include "libdnssec/binary.h"
21 #include "libdnssec/error.h"
22 #include "libdnssec/sign/der.h"
23 #include "libdnssec/shared/binary_wire.h"
24 
25 /*
26  * In fact, this is a very tiny subset of ASN.1 encoding format implementation,
27  * which is necessary for the purpose of DNSSEC.
28  *
29  * References: RFC 3279 (X.509 PKI), X.690, RFC 6605 (ECDSA), RFC8080 (EDDSA)
30  *
31  * Dss-Sig-Value ::= SEQUENCE { r INTEGER, s INTEGER }
32  */
33 
34 #define ASN1_TYPE_SEQUENCE 0x30
35 #define ASN1_TYPE_INTEGER  0x02
36 
37 #define ASN1_MAX_SIZE 127
38 
39 /*!
40  * Check if the next object has a given type.
41  */
asn1_expect_type(wire_ctx_t * wire,uint8_t type)42 static bool asn1_expect_type(wire_ctx_t *wire, uint8_t type)
43 {
44 	assert(wire);
45 	return (wire_ctx_available(wire) >= 1 && wire_ctx_read_u8(wire) == type);
46 }
47 
48 /*!
49  * Decode the size of the object (only short format is supported).
50  */
asn1_decode_size(wire_ctx_t * wire,size_t * size)51 static int asn1_decode_size(wire_ctx_t *wire, size_t *size)
52 {
53 	assert(wire);
54 	assert(size);
55 
56 	if (wire_ctx_available(wire) < 1) {
57 		return DNSSEC_MALFORMED_DATA;
58 	}
59 
60 	uint8_t byte = wire_ctx_read_u8(wire);
61 	if (byte & 0x80) {
62 		// long form, we do not need it for DNSSEC
63 		return DNSSEC_NOT_IMPLEMENTED_ERROR;
64 	}
65 
66 	*size = byte;
67 
68 	return DNSSEC_EOK;
69 }
70 
71 /*!
72  * Decode an unsigned integer object.
73  */
asn1_decode_integer(wire_ctx_t * wire,dnssec_binary_t * _value)74 static int asn1_decode_integer(wire_ctx_t *wire, dnssec_binary_t *_value)
75 {
76 	assert(wire);
77 	assert(_value);
78 
79 	if (!asn1_expect_type(wire, ASN1_TYPE_INTEGER)) {
80 		return DNSSEC_MALFORMED_DATA;
81 	}
82 
83 	size_t size;
84 	int result = asn1_decode_size(wire, &size);
85 	if (result != DNSSEC_EOK) {
86 		return result;
87 	}
88 
89 	if (size == 0 || size > wire_ctx_available(wire)) {
90 		return DNSSEC_MALFORMED_DATA;
91 	}
92 
93 	dnssec_binary_t value = { .data = wire->position, .size = size };
94 	wire->position += size;
95 
96 	// skip leading zeroes (unless equal to zero)
97 	while (value.size > 1 && value.data[0] == 0) {
98 		value.data += 1;
99 		value.size -= 1;
100 	}
101 
102 	*_value = value;
103 
104 	return DNSSEC_EOK;
105 }
106 
107 /*!
108  * Encode object header (type and length).
109  */
asn1_write_header(wire_ctx_t * wire,uint8_t type,size_t length)110 static void asn1_write_header(wire_ctx_t *wire, uint8_t type, size_t length)
111 {
112 	assert(wire);
113 	assert(length < ASN1_MAX_SIZE);
114 
115 	wire_ctx_write_u8(wire, type);
116 	wire_ctx_write_u8(wire, length);
117 }
118 
119 /*!
120  * Encode unsigned integer object.
121  */
asn1_write_integer(wire_ctx_t * wire,size_t integer_size,const dnssec_binary_t * integer)122 static void asn1_write_integer(wire_ctx_t *wire, size_t integer_size,
123 			       const dnssec_binary_t *integer)
124 {
125 	assert(wire);
126 	assert(integer);
127 	assert(integer->data);
128 
129 	asn1_write_header(wire, ASN1_TYPE_INTEGER, integer_size);
130 	bignum_write(wire, integer_size, integer);
131 }
132 
133 /*!
134  * Decode signature parameters from X.509 ECDSA signature.
135  */
dss_sig_value_decode(const dnssec_binary_t * der,dnssec_binary_t * r,dnssec_binary_t * s)136 int dss_sig_value_decode(const dnssec_binary_t *der,
137 			 dnssec_binary_t *r, dnssec_binary_t *s)
138 {
139 	if (!der || !der->data || !r || !s) {
140 		return DNSSEC_EINVAL;
141 	}
142 
143 	wire_ctx_t wire = binary_init(der);
144 
145 	size_t size;
146 	int result;
147 
148 	// decode the sequence
149 
150 	if (!asn1_expect_type(&wire, ASN1_TYPE_SEQUENCE)) {
151 		return DNSSEC_MALFORMED_DATA;
152 	}
153 
154 	result = asn1_decode_size(&wire, &size);
155 	if (result != DNSSEC_EOK) {
156 		return result;
157 	}
158 
159 	if (size != wire_ctx_available(&wire)) {
160 		return DNSSEC_MALFORMED_DATA;
161 	}
162 
163 	// decode the 'r' and 's' values
164 
165 	dnssec_binary_t der_r;
166 	result = asn1_decode_integer(&wire, &der_r);
167 	if (result != DNSSEC_EOK) {
168 		return result;
169 	}
170 
171 	dnssec_binary_t der_s;
172 	result = asn1_decode_integer(&wire, &der_s);
173 	if (result != DNSSEC_EOK) {
174 		return result;
175 	}
176 
177 	if (wire_ctx_available(&wire) != 0) {
178 		return DNSSEC_MALFORMED_DATA;
179 	}
180 
181 	*r = der_r;
182 	*s = der_s;
183 
184 	return DNSSEC_EOK;
185 }
186 
187 /*!
188  * Encode signature parameters from X.509 ECDSA signature.
189  */
dss_sig_value_encode(const dnssec_binary_t * r,const dnssec_binary_t * s,dnssec_binary_t * der)190 int dss_sig_value_encode(const dnssec_binary_t *r, const dnssec_binary_t *s,
191 			 dnssec_binary_t *der)
192 {
193 	if (!r || !r->data || !s || !s->data || !der) {
194 		return DNSSEC_EINVAL;
195 	}
196 
197 	size_t r_size = bignum_size_s(r);
198 	size_t s_size = bignum_size_s(s);
199 
200 	// check supported inputs range
201 
202 	if (r_size > ASN1_MAX_SIZE || s_size > ASN1_MAX_SIZE) {
203 		return DNSSEC_NOT_IMPLEMENTED_ERROR;
204 	}
205 
206 	size_t seq_size = 2 + r_size + 2 + s_size;
207 	if (seq_size > ASN1_MAX_SIZE) {
208 		return DNSSEC_NOT_IMPLEMENTED_ERROR;
209 	}
210 
211 	// encode result
212 
213 	size_t total_size = 2 + seq_size;
214 
215 	dnssec_binary_t _der = { 0 };
216 	if (dnssec_binary_alloc(&_der, total_size)) {
217 		return DNSSEC_ENOMEM;
218 	}
219 
220 	wire_ctx_t wire = binary_init(&_der);
221 	asn1_write_header(&wire, ASN1_TYPE_SEQUENCE, seq_size);
222 	asn1_write_integer(&wire, r_size, r);
223 	asn1_write_integer(&wire, s_size, s);
224 	assert(wire_ctx_available(&wire) == 0);
225 
226 	*der = _der;
227 
228 	return DNSSEC_EOK;
229 }
230