]> Git Repo - secp256k1.git/blob - contrib/lax_der_parsing.h
Merge pull request #334
[secp256k1.git] / contrib / lax_der_parsing.h
1 /**********************************************************************
2  * Copyright (c) 2015 Pieter Wuille                                   *
3  * Distributed under the MIT software license, see the accompanying   *
4  * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
5  **********************************************************************/
6
7 /* This file contains a code snippet that parses DER with various errors and
8  * violations. This is not a part of the library itself, because the allowed
9  * violations are chosen arbitrarily and do not follow or establish any
10  * standard.
11  *
12  * In many places it matters that different implementations do not only accept
13  * the same set of valid signatures, but also reject the same set of signatures.
14  * The only means to accomplish that is by strictly obeying a standard, and not
15  * accepting anything else.
16  *
17  * Nonetheless, sometimes there is a need for compatibility with systems that
18  * use signatures which do not strictly obey DER. The snippet below shows how
19  * certain violations are easily supported. You may need to adapt it.
20  *
21  * Do not use this for new systems. Use well-defined DER or compact signatures
22  * instead if you have the choice (see secp256k1_ecdsa_signature_parse_der and
23  * secp256k1_ecdsa_signature_parse_compact).
24  *
25  * The supported violations are:
26  * - All numbers are parsed as nonnegative integers, even though X.609-0207
27  *   section 8.3.3 specifies that integers are always encoded as two's
28  *   complement.
29  * - Integers can have length 0, even though section 8.3.1 says they can't.
30  * - Integers with overly long padding are accepted, violation section
31  *   8.3.2.
32  * - 127-byte long length descriptors are accepted, even though section
33  *   8.1.3.5.c says that they are not.
34  * - Trailing garbage data inside or after the signature is ignored.
35  * - The length descriptor of the sequence is ignored.
36  *
37  * Compared to for example OpenSSL, many violations are NOT supported:
38  * - Using overly long tag descriptors for the sequence or integers inside,
39  *   violating section 8.1.2.2.
40  * - Encoding primitive integers as constructed values, violating section
41  *   8.3.1.
42  */
43
44 #ifndef _SECP256K1_CONTRIB_LAX_DER_PARSING_H_
45 #define _SECP256K1_CONTRIB_LAX_DER_PARSING_H_
46
47 #include <string.h>
48 #include <secp256k1.h>
49
50 static int secp256k1_ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen);
51
52 static int secp256k1_ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) {
53     size_t rpos, rlen, spos, slen;
54     size_t pos = 0;
55     size_t lenbyte;
56     unsigned char tmpsig[64] = {0};
57     int overflow = 0;
58
59     /* Hack to initialize sig with a correctly-parsed but invalid signature. */
60     secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig);
61
62     /* Sequence tag byte */
63     if (pos == inputlen || input[pos] != 0x30) {
64         return 0;
65     }
66     pos++;
67
68     /* Sequence length bytes */
69     if (pos == inputlen) {
70         return 0;
71     }
72     lenbyte = input[pos++];
73     if (lenbyte & 0x80) {
74         lenbyte -= 0x80;
75         if (pos + lenbyte > inputlen) {
76             return 0;
77         }
78         pos += lenbyte;
79     }
80
81     /* Integer tag byte for R */
82     if (pos == inputlen || input[pos] != 0x02) {
83         return 0;
84     }
85     pos++;
86
87     /* Integer length for R */
88     if (pos == inputlen) {
89         return 0;
90     }
91     lenbyte = input[pos++];
92     if (lenbyte & 0x80) {
93         lenbyte -= 0x80;
94         if (pos + lenbyte > inputlen) {
95             return 0;
96         }
97         while (lenbyte > 0 && input[pos] == 0) {
98             pos++;
99             lenbyte--;
100         }
101         if (lenbyte >= sizeof(size_t)) {
102             return 0;
103         }
104         rlen = 0;
105         while (lenbyte > 0) {
106             rlen = (rlen << 8) + input[pos];
107             pos++;
108             lenbyte--;
109         }
110     } else {
111         rlen = lenbyte;
112     }
113     if (rlen > inputlen - pos) {
114         return 0;
115     }
116     rpos = pos;
117     pos += rlen;
118
119     /* Integer tag byte for S */
120     if (pos == inputlen || input[pos] != 0x02) {
121         return 0;
122     }
123     pos++;
124
125     /* Integer length for S */
126     if (pos == inputlen) {
127         return 0;
128     }
129     lenbyte = input[pos++];
130     if (lenbyte & 0x80) {
131         lenbyte -= 0x80;
132         if (pos + lenbyte > inputlen) {
133             return 0;
134         }
135         while (lenbyte > 0 && input[pos] == 0) {
136             pos++;
137             lenbyte--;
138         }
139         if (lenbyte >= sizeof(size_t)) {
140             return 0;
141         }
142         slen = 0;
143         while (lenbyte > 0) {
144             slen = (slen << 8) + input[pos];
145             pos++;
146             lenbyte--;
147         }
148     } else {
149         slen = lenbyte;
150     }
151     if (slen > inputlen - pos) {
152         return 0;
153     }
154     spos = pos;
155     pos += slen;
156
157     /* Ignore leading zeroes in R */
158     while (rlen > 0 && input[rpos] == 0) {
159         rlen--;
160         rpos++;
161     }
162     /* Copy R value */
163     if (rlen > 32) {
164         overflow = 1;
165     } else {
166         memcpy(tmpsig + 32 - rlen, input + rpos, rlen);
167     }
168
169     /* Ignore leading zeroes in S */
170     while (slen > 0 && input[spos] == 0) {
171         slen--;
172         spos++;
173     }
174     /* Copy S value */
175     if (slen > 32) {
176         overflow = 1;
177     } else {
178         memcpy(tmpsig + 64 - slen, input + spos, slen);
179     }
180
181     if (!overflow) {
182         overflow = !secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig);
183     }
184     if (overflow) {
185         memset(tmpsig, 0, 64);
186         secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig);
187     }
188     return 1;
189 }
190
191 #endif
This page took 0.035973 seconds and 4 git commands to generate.