aboutsummaryrefslogtreecommitdiffstats
path: root/test/monniaux/BearSSL/src/x509
diff options
context:
space:
mode:
Diffstat (limited to 'test/monniaux/BearSSL/src/x509')
-rw-r--r--test/monniaux/BearSSL/src/x509/asn1.t0757
-rw-r--r--test/monniaux/BearSSL/src/x509/asn1enc.c93
-rw-r--r--test/monniaux/BearSSL/src/x509/encode_ec_pk8der.c110
-rw-r--r--test/monniaux/BearSSL/src/x509/encode_ec_rawder.c161
-rw-r--r--test/monniaux/BearSSL/src/x509/encode_rsa_pk8der.c97
-rw-r--r--test/monniaux/BearSSL/src/x509/encode_rsa_rawder.c96
-rw-r--r--test/monniaux/BearSSL/src/x509/skey_decoder.c650
-rw-r--r--test/monniaux/BearSSL/src/x509/skey_decoder.t0373
-rw-r--r--test/monniaux/BearSSL/src/x509/x509_decoder.c773
-rw-r--r--test/monniaux/BearSSL/src/x509/x509_decoder.t0321
-rw-r--r--test/monniaux/BearSSL/src/x509/x509_knownkey.c105
-rw-r--r--test/monniaux/BearSSL/src/x509/x509_minimal.c1713
-rw-r--r--test/monniaux/BearSSL/src/x509/x509_minimal.t01508
-rw-r--r--test/monniaux/BearSSL/src/x509/x509_minimal_full.c59
14 files changed, 6816 insertions, 0 deletions
diff --git a/test/monniaux/BearSSL/src/x509/asn1.t0 b/test/monniaux/BearSSL/src/x509/asn1.t0
new file mode 100644
index 00000000..ba592526
--- /dev/null
+++ b/test/monniaux/BearSSL/src/x509/asn1.t0
@@ -0,0 +1,757 @@
+\ Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+\
+\ Permission is hereby granted, free of charge, to any person obtaining
+\ a copy of this software and associated documentation files (the
+\ "Software"), to deal in the Software without restriction, including
+\ without limitation the rights to use, copy, modify, merge, publish,
+\ distribute, sublicense, and/or sell copies of the Software, and to
+\ permit persons to whom the Software is furnished to do so, subject to
+\ the following conditions:
+\
+\ The above copyright notice and this permission notice shall be
+\ included in all copies or substantial portions of the Software.
+\
+\ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+\ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+\ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+\ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+\ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+\ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+\ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+\ SOFTWARE.
+
+\ =======================================================================
+
+\ This file contains code which is common to all engines that do some
+\ ASN.1 decoding. It should not be compiled on its own, but only along
+\ with another file (e.g. x509_minimal.t0) which uses it.
+\
+\ Users must define several things:
+\
+\ -- In the preamble, a macro called "CTX" that evaluates to the current
+\ context structure.
+\
+\ -- In the preamble, a macro called "CONTEXT_NAME" that evaluates to the
+\ context structure type. This will be invoked during compilation.
+\
+\ -- A word called "read8-low" ( -- x ) that reads the next byte, or -1
+\ if the input buffer is empty. That word is usually written in C.
+\
+\ -- A word called "read-blob-inner" ( addr len -- addr len ) that is
+\ the multi-byte version of read8-low.
+\
+\ -- A word called "skip-remaining-inner" ( lim -- lim ) which reads but
+\ drops some input bytes.
+
+preamble {
+
+#include "inner.h"
+
+}
+
+\ Read next source character, skipping blanks.
+: skip-blanks begin char dup 32 > if ret then drop again ;
+
+: fail-oid
+ "Invalid OID" puts cr exitvm ;
+
+\ Read a decimal integer, followed by either a dot or whitespace.
+\ Note: this does not check for overflows.
+: parse-number ( -- val nextchar )
+ char decval
+ begin
+ char
+ dup dup `. = swap 32 <= or if ret then
+ decval swap 10 * +
+ again ;
+
+\ Encode a number in unsigned 7E format.
+: encode7E ( val -- )
+ 0 encode7E-inner ;
+
+: encode7E-inner ( val eb -- )
+ swap dup 0x7F > if
+ dup 7 u>> 0x80 encode7E-inner 0x7F and
+ then
+ or data-add8 ;
+
+\ Decode an OID from source, and encode it. First byte is length,
+\ followed by encoded ASN.1 DER value. The OID is encoded in the
+\ current data block.
+: OID
+ \ Get current data address, and push a 0 for length.
+ current-data 0 data-add8
+ \ Skip blanks and get first digit, which must be 0, 1 or 2.
+ skip-blanks decval dup 2 > if fail-oid then
+ 40 *
+ \ Next character must be a dot.
+ char `. <> if fail-oid then
+ \ Second group must be one or two digits.
+ parse-number { nextchar }
+ dup 40 >= if fail-oid then
+ + encode7E
+ \ While next character is a dot, keep encoding numbers.
+ begin nextchar `. = while
+ parse-number >nextchar
+ encode7E
+ repeat
+ \ Write back length in the first byte.
+ dup current-data swap - 1- swap data-set8
+ ; immediate
+
+\ Define a new data word for an encoded OID. The OID is read from the
+\ source.
+: OID:
+ new-data-block next-word define-data-word postpone OID ;
+
+\ Define a word that evaluates to the address of a field within the
+\ context.
+: addr:
+ next-word { field }
+ "addr-" field + 0 1 define-word
+ 0 8191 "offsetof(CONTEXT_NAME, " field + ")" + make-CX
+ postpone literal postpone ; ;
+
+addr: pad
+
+\ Define a word that evaluates to an error code through a macro name.
+: err:
+ next-word { name }
+ name 0 1 define-word
+ 0 63 "BR_" name + make-CX postpone literal postpone ; ;
+
+err: ERR_X509_INVALID_VALUE
+err: ERR_X509_TRUNCATED
+err: ERR_X509_EMPTY_CHAIN
+err: ERR_X509_INNER_TRUNC
+err: ERR_X509_BAD_TAG_CLASS
+err: ERR_X509_BAD_TAG_VALUE
+err: ERR_X509_INDEFINITE_LENGTH
+err: ERR_X509_EXTRA_ELEMENT
+err: ERR_X509_UNEXPECTED
+err: ERR_X509_NOT_CONSTRUCTED
+err: ERR_X509_NOT_PRIMITIVE
+err: ERR_X509_PARTIAL_BYTE
+err: ERR_X509_BAD_BOOLEAN
+err: ERR_X509_OVERFLOW
+err: ERR_X509_BAD_DN
+err: ERR_X509_BAD_TIME
+err: ERR_X509_UNSUPPORTED
+err: ERR_X509_LIMIT_EXCEEDED
+err: ERR_X509_WRONG_KEY_TYPE
+err: ERR_X509_BAD_SIGNATURE
+err: ERR_X509_EXPIRED
+err: ERR_X509_DN_MISMATCH
+err: ERR_X509_BAD_SERVER_NAME
+err: ERR_X509_CRITICAL_EXTENSION
+err: ERR_X509_NOT_CA
+err: ERR_X509_FORBIDDEN_KEY_USAGE
+err: ERR_X509_WEAK_PUBLIC_KEY
+
+: KEYTYPE_RSA CX 0 15 { BR_KEYTYPE_RSA } ;
+: KEYTYPE_EC CX 0 15 { BR_KEYTYPE_EC } ;
+
+cc: fail ( err -- ! ) {
+ CTX->err = T0_POPi();
+ T0_CO();
+}
+
+\ Read one byte from the stream.
+: read8-nc ( -- x )
+ begin
+ read8-low dup 0 >= if ret then
+ drop co
+ again ;
+
+\ Read one byte, enforcing current read limit.
+: read8 ( lim -- lim x )
+ dup ifnot ERR_X509_INNER_TRUNC fail then
+ 1- read8-nc ;
+
+\ Read a 16-bit value, big-endian encoding.
+: read16be ( lim -- lim x )
+ read8 8 << swap read8 rot + ;
+
+\ Read a 16-bit value, little-endian encoding.
+: read16le ( lim -- lim x )
+ read8 swap read8 8 << rot + ;
+
+\ Read all bytes from the current element, then close it (i.e. drop the
+\ limit). Destination address is an offset within the context.
+: read-blob ( lim addr -- )
+ swap
+ begin dup while read-blob-inner dup if co then repeat
+ 2drop ;
+
+\ Skip remaining bytes in the current structure, but do not close it
+\ (thus, this leaves the value 0 on the stack).
+: skip-remaining ( lim -- lim )
+ begin dup while skip-remaining-inner dup if co then repeat ;
+
+: skip-remaining-inner ( lim -- lim )
+ 0 over read-blob-inner -rot 2drop ;
+
+cc: set8 ( val addr -- ) {
+ uint32_t addr = T0_POP();
+ *((unsigned char *)CTX + addr) = (unsigned char)T0_POP();
+}
+
+cc: set16 ( val addr -- ) {
+ uint32_t addr = T0_POP();
+ *(uint16_t *)(void *)((unsigned char *)CTX + addr) = T0_POP();
+}
+
+cc: set32 ( val addr -- ) {
+ uint32_t addr = T0_POP();
+ *(uint32_t *)(void *)((unsigned char *)CTX + addr) = T0_POP();
+}
+
+cc: get8 ( addr -- val ) {
+ uint32_t addr = T0_POP();
+ T0_PUSH(*((unsigned char *)CTX + addr));
+}
+
+cc: get16 ( addr -- val ) {
+ uint32_t addr = T0_POP();
+ T0_PUSH(*(uint16_t *)(void *)((unsigned char *)CTX + addr));
+}
+
+cc: get32 ( addr -- val ) {
+ uint32_t addr = T0_POP();
+ T0_PUSH(*(uint32_t *)(void *)((unsigned char *)CTX + addr));
+}
+
+\ Read an ASN.1 tag. This function returns the "constructed" status
+\ and the tag value. The constructed status is a boolean (-1 for
+\ constructed, 0 for primitive). The tag value is either 0 to 31 for
+\ a universal tag, or 32+x for a contextual tag of value x. Tag classes
+\ "application" and "private" are rejected. Universal tags beyond 30
+\ are rejected. Contextual tags beyond 30 are rejected. Thus, accepted
+\ tags will necessarily fit on exactly one byte. This does not support
+\ the whole of ASN.1/BER, but is sufficient for certificate parsing.
+: read-tag ( lim -- lim constructed value )
+ read8 { fb }
+
+ \ Constructed flag is bit 5.
+ fb 5 >> 0x01 and neg
+
+ \ Class is in bits 6 and 7. Accepted classes are 00 (universal)
+ \ and 10 (context). We check that bit 6 is 0, and shift back
+ \ bit 7 so that we get 0 (universal) or 32 (context).
+ fb 6 >> dup 0x01 and if ERR_X509_BAD_TAG_CLASS fail then
+ 4 <<
+
+ \ Tag value is in bits 0..4. If the value is 31, then this is
+ \ an extended tag, encoded over subsequent bytes, and we do
+ \ not support that.
+ fb 0x1F and dup 0x1F = if ERR_X509_BAD_TAG_VALUE fail then
+ + ;
+
+\ Read a tag, but only if not at the end of the current object. If there
+\ is no room for another element (limit is zero), then this will push a
+\ synthetic "no tag" value (primitive, with value -1).
+: read-tag-or-end ( lim -- lim constructed value )
+ dup ifnot 0 -1 ret then
+ read-tag ;
+
+\ Compare the read tag with the provided value. If equal, then the
+\ element is skipped, and a new tag is read (or end of object).
+: iftag-skip ( lim constructed value ref -- lim constructed value )
+ over = if
+ 2drop
+ read-length-open-elt skip-close-elt
+ read-tag-or-end
+ then ;
+
+\ Read an ASN.1 length. This supports only definite lengths (theoretically,
+\ certificates may use an indefinite length for the outer structure, using
+\ DER only in the TBS, but this never happens in practice, except in a
+\ single example certificate from 15 years ago that also fails to decode
+\ properly for other reasons).
+: read-length ( lim -- lim length )
+ read8
+ \ Lengths in 0x00..0x7F get encoded as a single byte.
+ dup 0x80 < if ret then
+
+ \ If the byte is 0x80 then this is an indefinite length, and we
+ \ do not support that.
+ 0x80 - dup ifnot ERR_X509_INDEFINITE_LENGTH fail then
+
+ \ Masking out bit 7, this yields the number of bytes over which
+ \ the value is encoded. Since the total certificate length must
+ \ fit over 3 bytes (this is a consequence of SSL/TLS message
+ \ format), we can reject big lengths and keep the length in a
+ \ single integer.
+ { n } 0
+ begin n 0 > while n 1- >n
+ dup 0x7FFFFF > if ERR_X509_INNER_TRUNC fail then
+ 8 << swap read8 rot +
+ repeat ;
+
+\ Open a sub-structure. This subtracts the length from the limit, and
+\ pushes the length back as new limit.
+: open-elt ( lim length -- lim_outer lim_inner )
+ dup2 < if ERR_X509_INNER_TRUNC fail then
+ dup { len } - len ;
+
+\ Read a length and open the value as a sub-structure.
+: read-length-open-elt ( lim -- lim_outer lim_inner )
+ read-length open-elt ;
+
+\ Close a sub-structure. This verifies that there is no remaining
+\ element to read.
+: close-elt ( lim -- )
+ if ERR_X509_EXTRA_ELEMENT fail then ;
+
+\ Skip remaining bytes in the current structure, then close it.
+: skip-close-elt ( lim -- )
+ skip-remaining drop ;
+
+\ Read a length and then skip the value.
+: read-length-skip ( lim -- lim )
+ read-length-open-elt skip-close-elt ;
+
+\ Check that a given tag is constructed and has the expected value.
+: check-tag-constructed ( constructed value refvalue -- )
+ = ifnot ERR_X509_UNEXPECTED fail then
+ check-constructed ;
+
+\ Check that the top value is true; report a "not constructed"
+\ error otherwise.
+: check-constructed ( constructed -- )
+ ifnot ERR_X509_NOT_CONSTRUCTED fail then ;
+
+\ Check that a given tag is primitive and has the expected value.
+: check-tag-primitive ( constructed value refvalue -- )
+ = ifnot ERR_X509_UNEXPECTED fail then
+ check-primitive ;
+
+\ Check that the top value is true; report a "not primitive"
+\ error otherwise.
+: check-primitive ( constructed -- )
+ if ERR_X509_NOT_PRIMITIVE fail then ;
+
+\ Check that the tag is for a constructed SEQUENCE.
+: check-sequence ( constructed value -- )
+ 0x10 check-tag-constructed ;
+
+\ Read a tag, check that it is for a constructed SEQUENCE, and open
+\ it as a sub-element.
+: read-sequence-open ( lim -- lim_outer lim_inner )
+ read-tag check-sequence read-length-open-elt ;
+
+\ Read the next element as a BIT STRING with no ignore bits, and open
+\ it as a sub-element.
+: read-bits-open ( lim -- lim_outer lim_inner )
+ read-tag 0x03 check-tag-primitive
+ read-length-open-elt
+ read8 if ERR_X509_PARTIAL_BYTE fail then ;
+
+OID: rsaEncryption 1.2.840.113549.1.1.1
+
+OID: sha1WithRSAEncryption 1.2.840.113549.1.1.5
+OID: sha224WithRSAEncryption 1.2.840.113549.1.1.14
+OID: sha256WithRSAEncryption 1.2.840.113549.1.1.11
+OID: sha384WithRSAEncryption 1.2.840.113549.1.1.12
+OID: sha512WithRSAEncryption 1.2.840.113549.1.1.13
+
+OID: id-sha1 1.3.14.3.2.26
+OID: id-sha224 2.16.840.1.101.3.4.2.4
+OID: id-sha256 2.16.840.1.101.3.4.2.1
+OID: id-sha384 2.16.840.1.101.3.4.2.2
+OID: id-sha512 2.16.840.1.101.3.4.2.3
+
+OID: id-ecPublicKey 1.2.840.10045.2.1
+
+OID: ansix9p256r1 1.2.840.10045.3.1.7
+OID: ansix9p384r1 1.3.132.0.34
+OID: ansix9p521r1 1.3.132.0.35
+
+OID: ecdsa-with-SHA1 1.2.840.10045.4.1
+OID: ecdsa-with-SHA224 1.2.840.10045.4.3.1
+OID: ecdsa-with-SHA256 1.2.840.10045.4.3.2
+OID: ecdsa-with-SHA384 1.2.840.10045.4.3.3
+OID: ecdsa-with-SHA512 1.2.840.10045.4.3.4
+
+OID: id-at-commonName 2.5.4.3
+
+\ Read a "small value". This assumes that the tag has just been read
+\ and processed, but not the length. The first pad byte is set to the
+\ value length; the encoded value itself follows. If the value length
+\ exceeds 255 bytes, then a single 0 is written in the pad, and this
+\ method returns false (0). Otherwise, it returns true (-1).
+\ Either way, the element is fully read.
+: read-small-value ( lim -- lim bool )
+ read-length-open-elt
+ dup 255 > if skip-close-elt 0 addr-pad set8 0 ret then
+ dup addr-pad set8
+ addr-pad 1+ read-blob
+ -1 ;
+
+\ Read an OID as a "small value" (tag, length and value). A boolean
+\ value is returned, which is true (-1) if the OID value fits on the pad,
+\ false (0) otherwise.
+: read-OID ( lim -- lim bool )
+ read-tag 0x06 check-tag-primitive read-small-value ;
+
+\ Read a UTF-8 code point. On error, return 0. Reading a code point of
+\ value 0 is considered to be an error.
+: read-UTF8 ( lim -- lim val )
+ read8
+ choice
+ dup 0x80 < uf ret enduf
+ dup 0xC0 < uf drop 0 ret enduf
+ dup 0xE0 < uf 0x1F and 1 read-UTF8-next 0x80 0x7FF enduf
+ dup 0xF0 < uf 0x0F and 2 read-UTF8-next 0x800 0xFFFF enduf
+ dup 0xF8 < uf 0x07 and 3 read-UTF8-next 0x10000 0x10FFFF enduf
+ drop 0 ret
+ endchoice
+ between? ifnot drop 0 then
+ ;
+
+\ Read n subsequent bytes to complete the provided first byte. The final
+\ value is -1 on error, or the code point numerical value. The final
+\ value is duplicated.
+: read-UTF8-next ( lim val n -- lim val val )
+ begin dup while
+ -rot
+ read-UTF8-chunk
+ rot 1-
+ repeat
+ drop dup ;
+
+\ Read one byte, that should be a trailing UTF-8 byte, and complement the
+\ current value. On error, value is set to -1.
+: read-UTF8-chunk ( lim val -- lim val )
+ swap
+ \ If we are at the end of the value, report an error but don't fail.
+ dup ifnot 2drop 0 -1 ret then
+ read8 rot
+ dup 0< if swap drop ret then 6 <<
+ swap dup 6 >> 2 <> if 2drop -1 ret then
+ 0x3F and + ;
+
+: high-surrogate? ( x -- x bool )
+ dup 0xD800 0xDBFF between? ;
+
+: low-surrogate? ( x -- x bool )
+ dup 0xDC00 0xDFFF between? ;
+
+: assemble-surrogate-pair ( hi lim lo -- lim val )
+ low-surrogate? ifnot rot 2drop 0 ret then
+ rot 10 << + 0x35FDC00 - ;
+
+\ Read a UTF-16 code point (big-endian). Returned value is 0 on error.
+: read-UTF16BE ( lim -- lim val )
+ read16be
+ choice
+ high-surrogate? uf
+ swap dup ifnot 2drop 0 0 ret then
+ read16be assemble-surrogate-pair
+ enduf
+ low-surrogate? uf
+ drop 0
+ enduf
+ endchoice ;
+
+\ Read a UTF-16 code point (little-endian). Returned value is 0 on error.
+: read-UTF16LE ( lim -- lim val )
+ read16le
+ choice
+ high-surrogate? uf
+ swap dup ifnot 2drop 0 0 ret then
+ read16le assemble-surrogate-pair
+ enduf
+ low-surrogate? uf
+ drop 0
+ enduf
+ endchoice ;
+
+\ Add byte to current pad value. Offset is updated, or set to 0 on error.
+: pad-append ( off val -- off )
+ over dup 0= swap 256 >= or if 2drop 0 ret then
+ over addr-pad + set8 1+ ;
+
+\ Add UTF-8 chunk byte to the pad. The 'nn' parameter is the shift count.
+: pad-append-UTF8-chunk ( off val nn -- off )
+ >> 0x3F and 0x80 or pad-append ;
+
+\ Test whether a code point is invalid when encoding. This rejects the
+\ 66 noncharacters, and also the surrogate range; this function does NOT
+\ check that the value is in the 0..10FFFF range.
+: valid-unicode? ( val -- bool )
+ dup 0xFDD0 0xFEDF between? if drop 0 ret then
+ dup 0xD800 0xDFFF between? if drop 0 ret then
+ 0xFFFF and 0xFFFE < ;
+
+\ Encode a code point in UTF-8. Offset is in the pad; it is updated, or
+\ set to 0 on error. Leading BOM are ignored.
+: encode-UTF8 ( val off -- off )
+ \ Skip leading BOM (U+FEFF when off is 1).
+ dup2 1 = swap 0xFEFF = and if swap drop ret then
+
+ swap dup { val }
+ dup valid-unicode? ifnot 2drop 0 ret then
+ choice
+ dup 0x80 < uf pad-append enduf
+ dup 0x800 < uf
+ 6 >> 0xC0 or pad-append
+ val 0 pad-append-UTF8-chunk
+ enduf
+ dup 0xFFFF < uf
+ 12 >> 0xE0 or pad-append
+ val 6 pad-append-UTF8-chunk
+ val 0 pad-append-UTF8-chunk
+ enduf
+ 18 >> 0xF0 or pad-append
+ val 12 pad-append-UTF8-chunk
+ val 6 pad-append-UTF8-chunk
+ val 0 pad-append-UTF8-chunk
+ endchoice ;
+
+\ Read a string value into the pad; this function checks that the source
+\ characters are UTF-8 and non-zero. The string length (in bytes) is
+\ written in the first pad byte. Returned value is true (-1) on success,
+\ false (0) on error.
+: read-value-UTF8 ( lim -- lim bool )
+ read-length-open-elt
+ 1 { off }
+ begin dup while
+ read-UTF8 dup ifnot drop skip-close-elt 0 ret then
+ off encode-UTF8 >off
+ repeat
+ drop off dup ifnot ret then 1- addr-pad set8 -1 ;
+
+\ Decode a UTF-16 string into the pad. The string is converted to UTF-8,
+\ and the length is written in the first pad byte. A leading BOM is
+\ honoured (big-endian is assumed if there is no BOM). A code point of
+\ value 0 is an error. Returned value is true (-1) on success, false (0)
+\ on error.
+: read-value-UTF16 ( lim -- lim bool )
+ read-length-open-elt
+ dup ifnot addr-pad set8 -1 ret then
+ 1 { off }
+ read-UTF16BE dup 0xFFFE = if
+ \ Leading BOM, and indicates little-endian.
+ drop
+ begin dup while
+ read-UTF16LE dup ifnot drop skip-close-elt 0 ret then
+ off encode-UTF8 >off
+ repeat
+ else
+ dup ifnot drop skip-close-elt 0 ret then
+ \ Big-endian BOM, or no BOM.
+ begin
+ off encode-UTF8 >off
+ dup while
+ read-UTF16BE dup ifnot drop skip-close-elt 0 ret then
+ repeat
+ then
+ drop off dup ifnot ret then 1- addr-pad set8 -1 ;
+
+\ Decode a latin-1 string into the pad. The string is converted to UTF-8,
+\ and the length is written in the first pad byte. A source byte of
+\ value 0 is an error. Returned value is true (-1) on success, false (0)
+\ on error.
+: read-value-latin1 ( lim -- lim bool )
+ read-length-open-elt
+ 1 { off }
+ begin dup while
+ read8 dup ifnot drop skip-close-elt 0 ret then
+ off encode-UTF8 >off
+ repeat
+ drop off dup ifnot ret then 1- addr-pad set8 -1 ;
+
+\ Read a value and interpret it as an INTEGER or ENUMERATED value. If
+\ the integer value does not fit on an unsigned 32-bit value, an error
+\ is reported. This function assumes that the tag has just been read
+\ and processed, but not the length.
+: read-small-int-value ( lim -- lim x )
+ read-length-open-elt
+ dup ifnot ERR_X509_OVERFLOW fail then
+ read8 dup 0x80 >= if ERR_X509_OVERFLOW fail then
+ { x }
+ begin dup while
+ read8 x dup 0xFFFFFF >= if ERR_X509_OVERFLOW fail then
+ 8 << + >x
+ repeat
+ drop x ;
+
+\ Compare the OID in the pad with an OID in the constant data block.
+\ Returned value is -1 on equality, 0 otherwise.
+cc: eqOID ( addrConst -- bool ) {
+ const unsigned char *a2 = &t0_datablock[T0_POP()];
+ const unsigned char *a1 = &CTX->pad[0];
+ size_t len = a1[0];
+ int x;
+ if (len == a2[0]) {
+ x = -(memcmp(a1 + 1, a2 + 1, len) == 0);
+ } else {
+ x = 0;
+ }
+ T0_PUSH((uint32_t)x);
+}
+
+\ Compare two blobs in the context. Returned value is -1 on equality, 0
+\ otherwise.
+cc: eqblob ( addr1 addr2 len -- bool ) {
+ size_t len = T0_POP();
+ const unsigned char *a2 = (const unsigned char *)CTX + T0_POP();
+ const unsigned char *a1 = (const unsigned char *)CTX + T0_POP();
+ T0_PUSHi(-(memcmp(a1, a2, len) == 0));
+}
+
+\ Check that a value is in a given range (inclusive).
+: between? ( x min max -- bool )
+ { min max } dup min >= swap max <= and ;
+
+\ Convert the provided byte value into a number in the 0..9 range,
+\ assuming that it is an ASCII digit. A non-digit triggers an error
+\ (a "bad time" error since this is used in date/time decoding).
+: digit-dec ( char -- value )
+ `0 - dup 0 9 between? ifnot ERR_X509_BAD_TIME fail then ;
+
+\ Read two ASCII digits and return the value in the 0..99 range. An
+\ error is reported if the characters are not ASCII digits.
+: read-dec2 ( lim -- lim x )
+ read8 digit-dec 10 * { x } read8 digit-dec x + ;
+
+\ Read two ASCII digits and check that the value is in the provided
+\ range (inclusive).
+: read-dec2-range ( lim min max -- lim x )
+ { min max }
+ read-dec2 dup min max between? ifnot ERR_X509_BAD_TIME fail then ;
+
+\ Maximum days in a month and accumulated day count. Each
+\ 16-bit value contains the month day count in its lower 5 bits. The first
+\ 12 values are for a normal year, the other 12 for a leap year.
+data: month-to-days
+hexb| 001F 03FC 077F 0B5E 0F1F 12FE 16BF 1A9F 1E7E 223F 261E 29DF |
+hexb| 001F 03FD 079F 0B7E 0F3F 131E 16DF 1ABF 1E9E 225F 263E 29FF |
+
+\ Read a date (UTCTime or GeneralizedTime). The date value is converted
+\ to a day count and a second count. The day count starts at 0 for
+\ January 1st, 0 AD (that's they year before 1 AD, also known as 1 BC)
+\ in a proleptic Gregorian calendar (i.e. Gregorian rules are assumed to
+\ extend indefinitely in the past). The second count is between 0 and
+\ 86400 (inclusive, in case of a leap second).
+: read-date ( lim -- lim days seconds )
+ \ Read tag; must be UTCTime or GeneralizedTime. Year count is
+ \ 4 digits with GeneralizedTime, 2 digits with UTCTime.
+ read-tag
+ dup 0x17 0x18 between? ifnot ERR_X509_BAD_TIME fail then
+ 0x18 = { y4d }
+ check-primitive
+ read-length-open-elt
+
+ \ We compute the days and seconds counts during decoding, in
+ \ order to minimize the number of needed temporary variables.
+ { ; days seconds x }
+
+ \ Year is 4-digit with GeneralizedTime. With UTCTime, the year
+ \ is in the 1950..2049 range, and only the last two digits are
+ \ present in the encoding.
+ read-dec2
+ y4d if
+ 100 * >x read-dec2 x +
+ else
+ dup 50 < if 100 + then 1900 +
+ then
+ >x
+ x 365 * x 3 + 4 / + x 99 + 100 / - x 399 + 400 / + >days
+
+ \ Month is 1..12. Number of days in a months depend on the
+ \ month and on the year (year count is in x at that point).
+ 1 12 read-dec2-range
+ 1- 1 <<
+ x 4 % 0= x 100 % 0<> x 400 % 0= or and if 24 + then
+ month-to-days + data-get16
+ dup 5 >> days + >days
+ 0x1F and
+
+ \ Day. At this point, the TOS contains the maximum day count for
+ \ the current month.
+ 1 swap read-dec2-range
+ days + 1- >days
+
+ \ Hour, minute and seconds. Count of seconds is allowed to go to
+ \ 60 in case of leap seconds (in practice, leap seconds really
+ \ occur only at the very end of the day, so this computation is
+ \ exact for a real leap second, and a spurious leap second only
+ \ implies a one-second shift that we can ignore).
+ 0 23 read-dec2-range 3600 * >seconds
+ 0 59 read-dec2-range 60 * seconds + >seconds
+ 0 60 read-dec2-range seconds + >seconds
+
+ \ At this point, we may have fractional seconds. This should
+ \ happen only with GeneralizedTime, but we accept it for UTCTime
+ \ too (and, anyway, we ignore these fractional seconds).
+ read8 dup `. = if
+ drop
+ begin read8 dup `0 `9 between? while drop repeat
+ then
+
+ \ The time zone should be 'Z', not followed by anything. Other
+ \ time zone indications are not DER and thus not supposed to
+ \ appear in certificates.
+ `Z <> if ERR_X509_BAD_TIME fail then
+ close-elt
+ days seconds ;
+
+\ Read an INTEGER (tag, length and value). The INTEGER is supposed to be
+\ positive; its unsigned big-endian encoding is stored in the provided
+\ in-context buffer. Returned value is the decoded length. If the integer
+\ did not fit, or the value is negative, then an error is reported.
+: read-integer ( lim addr len -- lim dlen )
+ rot read-tag 0x02 check-tag-primitive -rot
+ read-integer-next ;
+
+\ Identical to read-integer, but the tag has already been read and checked.
+: read-integer-next ( lim addr len -- lim dlen )
+ dup { addr len origlen }
+ read-length-open-elt
+ \ Read first byte; sign bit must be 0.
+ read8 dup 0x80 >= if ERR_X509_OVERFLOW fail then
+ \ Skip leading bytes of value 0. If there are only bytes of
+ \ value 0, then return.
+ begin dup 0 = while
+ drop dup ifnot drop 0 ret then
+ read8
+ repeat
+ \ At that point, we have the first non-zero byte on the stack.
+ begin
+ len dup ifnot ERR_X509_LIMIT_EXCEEDED fail then 1- >len
+ addr set8 addr 1+ >addr
+ dup while read8
+ repeat
+ drop origlen len - ;
+
+\ Read a BOOLEAN value. This should be called immediately after reading
+\ the tag.
+: read-boolean ( lim constructed value -- lim bool )
+ 0x01 check-tag-primitive
+ read-length 1 <> if ERR_X509_BAD_BOOLEAN fail then
+ read8 0<> ;
+
+\ Identify an elliptic curve: read the OID, then check it against the
+\ known curve OID.
+: read-curve-ID ( lim -- lim curve )
+ read-OID ifnot ERR_X509_UNSUPPORTED fail then
+ choice
+ ansix9p256r1 eqOID uf 23 enduf
+ ansix9p384r1 eqOID uf 24 enduf
+ ansix9p521r1 eqOID uf 25 enduf
+ ERR_X509_UNSUPPORTED fail
+ endchoice ;
+
+\ A convenient debug word: print the current data stack contents.
+cc: DEBUG ( -- ) {
+ extern int printf(const char *fmt, ...);
+ uint32_t *p;
+
+ printf("<stack:");
+ for (p = &CTX->dp_stack[0]; p != dp; p ++) {
+ printf(" %lu", (unsigned long)*p);
+ }
+ printf(" >\n");
+}
diff --git a/test/monniaux/BearSSL/src/x509/asn1enc.c b/test/monniaux/BearSSL/src/x509/asn1enc.c
new file mode 100644
index 00000000..7a749633
--- /dev/null
+++ b/test/monniaux/BearSSL/src/x509/asn1enc.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+br_asn1_uint
+br_asn1_uint_prepare(const void *xdata, size_t xlen)
+{
+ const unsigned char *x;
+ br_asn1_uint t;
+
+ x = xdata;
+ while (xlen > 0 && *x == 0) {
+ x ++;
+ xlen --;
+ }
+ t.data = x;
+ t.len = xlen;
+ t.asn1len = xlen;
+ if (xlen == 0 || x[0] >= 0x80) {
+ t.asn1len ++;
+ }
+ return t;
+}
+
+/* see inner.h */
+size_t
+br_asn1_encode_length(void *dest, size_t len)
+{
+ unsigned char *buf;
+ size_t z;
+ int i, j;
+
+ buf = dest;
+ if (len < 0x80) {
+ if (buf != NULL) {
+ *buf = len;
+ }
+ return 1;
+ }
+ i = 0;
+ for (z = len; z != 0; z >>= 8) {
+ i ++;
+ }
+ if (buf != NULL) {
+ *buf ++ = 0x80 + i;
+ for (j = i - 1; j >= 0; j --) {
+ *buf ++ = len >> (j << 3);
+ }
+ }
+ return i + 1;
+}
+
+/* see inner.h */
+size_t
+br_asn1_encode_uint(void *dest, br_asn1_uint pp)
+{
+ unsigned char *buf;
+ size_t lenlen;
+
+ if (dest == NULL) {
+ return 1 + br_asn1_encode_length(NULL, pp.asn1len) + pp.asn1len;
+ }
+ buf = dest;
+ *buf ++ = 0x02;
+ lenlen = br_asn1_encode_length(buf, pp.asn1len);
+ buf += lenlen;
+ *buf = 0x00;
+ memcpy(buf + pp.asn1len - pp.len, pp.data, pp.len);
+ return 1 + lenlen + pp.asn1len;
+}
diff --git a/test/monniaux/BearSSL/src/x509/encode_ec_pk8der.c b/test/monniaux/BearSSL/src/x509/encode_ec_pk8der.c
new file mode 100644
index 00000000..53717ce3
--- /dev/null
+++ b/test/monniaux/BearSSL/src/x509/encode_ec_pk8der.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_x509.h */
+size_t
+br_encode_ec_pkcs8_der(void *dest,
+ const br_ec_private_key *sk, const br_ec_public_key *pk)
+{
+ /*
+ * ASN.1 format:
+ *
+ * OneAsymmetricKey ::= SEQUENCE {
+ * version Version,
+ * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
+ * privateKey PrivateKey,
+ * attributes [0] Attributes OPTIONAL,
+ * ...,
+ * [[2: publicKey [1] PublicKey OPTIONAL ]],
+ * ...
+ * }
+ *
+ * We don't include attributes or public key (the public key
+ * is included in the private key value instead). The
+ * 'version' field is an INTEGER that we will set to 0
+ * (meaning 'v1', compatible with previous versions of PKCS#8).
+ * The 'privateKeyAlgorithm' structure is an AlgorithmIdentifier
+ * whose OID should be id-ecPublicKey, with, as parameters, the
+ * curve OID. The 'privateKey' is an OCTET STRING, whose value
+ * is the "raw DER" encoding of the key pair.
+ */
+
+ /*
+ * OID id-ecPublicKey (1.2.840.10045.2.1), DER-encoded (with
+ * the tag).
+ */
+ static const unsigned char OID_ECPUBKEY[] = {
+ 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01
+ };
+
+ size_t len_version, len_privateKeyAlgorithm, len_privateKeyValue;
+ size_t len_privateKey, len_seq;
+ const unsigned char *oid;
+
+ oid = br_get_curve_OID(sk->curve);
+ if (oid == NULL) {
+ return 0;
+ }
+ len_version = 3;
+ len_privateKeyAlgorithm = 2 + sizeof OID_ECPUBKEY + 2 + oid[0];
+ len_privateKeyValue = br_encode_ec_raw_der_inner(NULL, sk, pk, 0);
+ len_privateKey = 1 + len_of_len(len_privateKeyValue)
+ + len_privateKeyValue;
+ len_seq = len_version + len_privateKeyAlgorithm + len_privateKey;
+
+ if (dest == NULL) {
+ return 1 + len_of_len(len_seq) + len_seq;
+ } else {
+ unsigned char *buf;
+ size_t lenlen;
+
+ buf = dest;
+ *buf ++ = 0x30; /* SEQUENCE tag */
+ lenlen = br_asn1_encode_length(buf, len_seq);
+ buf += lenlen;
+
+ /* version */
+ *buf ++ = 0x02;
+ *buf ++ = 0x01;
+ *buf ++ = 0x00;
+
+ /* privateKeyAlgorithm */
+ *buf ++ = 0x30;
+ *buf ++ = (sizeof OID_ECPUBKEY) + 2 + oid[0];
+ memcpy(buf, OID_ECPUBKEY, sizeof OID_ECPUBKEY);
+ buf += sizeof OID_ECPUBKEY;
+ *buf ++ = 0x06;
+ memcpy(buf, oid, 1 + oid[0]);
+ buf += 1 + oid[0];
+
+ /* privateKey */
+ *buf ++ = 0x04;
+ buf += br_asn1_encode_length(buf, len_privateKeyValue);
+ br_encode_ec_raw_der_inner(buf, sk, pk, 0);
+
+ return 1 + lenlen + len_seq;
+ }
+}
diff --git a/test/monniaux/BearSSL/src/x509/encode_ec_rawder.c b/test/monniaux/BearSSL/src/x509/encode_ec_rawder.c
new file mode 100644
index 00000000..5985909a
--- /dev/null
+++ b/test/monniaux/BearSSL/src/x509/encode_ec_rawder.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+const unsigned char *
+br_get_curve_OID(int curve)
+{
+ static const unsigned char OID_secp256r1[] = {
+ 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07
+ };
+ static const unsigned char OID_secp384r1[] = {
+ 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22
+ };
+ static const unsigned char OID_secp521r1[] = {
+ 0x05, 0x2b, 0x81, 0x04, 0x00, 0x23
+ };
+
+ switch (curve) {
+ case BR_EC_secp256r1: return OID_secp256r1;
+ case BR_EC_secp384r1: return OID_secp384r1;
+ case BR_EC_secp521r1: return OID_secp521r1;
+ default:
+ return NULL;
+ }
+}
+
+/* see inner.h */
+size_t
+br_encode_ec_raw_der_inner(void *dest,
+ const br_ec_private_key *sk, const br_ec_public_key *pk,
+ int include_curve_oid)
+{
+ /*
+ * ASN.1 format:
+ *
+ * ECPrivateKey ::= SEQUENCE {
+ * version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
+ * privateKey OCTET STRING,
+ * parameters [0] ECParameters {{ NamedCurve }} OPTIONAL,
+ * publicKey [1] BIT STRING OPTIONAL
+ * }
+ *
+ * The tages '[0]' and '[1]' are explicit. The 'ECParameters'
+ * is a CHOICE; in our case, it will always be an OBJECT IDENTIFIER
+ * that identifies the curve.
+ *
+ * The value of the 'privateKey' field is the raw unsigned big-endian
+ * encoding of the private key (integer modulo the curve subgroup
+ * order); there is no INTEGER tag, and the leading bit may be 1.
+ * Also, leading bytes of value 0x00 are _not_ removed.
+ *
+ * The 'publicKey' contents are the raw encoded public key point,
+ * normally uncompressed (leading byte of value 0x04, followed
+ * by the unsigned big-endian encodings of the X and Y coordinates,
+ * padded to the full field length if necessary).
+ */
+
+ size_t len_version, len_privateKey, len_parameters, len_publicKey;
+ size_t len_publicKey_bits, len_seq;
+ const unsigned char *oid;
+
+ if (include_curve_oid) {
+ oid = br_get_curve_OID(sk->curve);
+ if (oid == NULL) {
+ return 0;
+ }
+ } else {
+ oid = NULL;
+ }
+ len_version = 3;
+ len_privateKey = 1 + len_of_len(sk->xlen) + sk->xlen;
+ if (include_curve_oid) {
+ len_parameters = 4 + oid[0];
+ } else {
+ len_parameters = 0;
+ }
+ if (pk == NULL) {
+ len_publicKey = 0;
+ len_publicKey_bits = 0;
+ } else {
+ len_publicKey_bits = 2 + len_of_len(pk->qlen) + pk->qlen;
+ len_publicKey = 1 + len_of_len(len_publicKey_bits)
+ + len_publicKey_bits;
+ }
+ len_seq = len_version + len_privateKey + len_parameters + len_publicKey;
+ if (dest == NULL) {
+ return 1 + len_of_len(len_seq) + len_seq;
+ } else {
+ unsigned char *buf;
+ size_t lenlen;
+
+ buf = dest;
+ *buf ++ = 0x30; /* SEQUENCE tag */
+ lenlen = br_asn1_encode_length(buf, len_seq);
+ buf += lenlen;
+
+ /* version */
+ *buf ++ = 0x02;
+ *buf ++ = 0x01;
+ *buf ++ = 0x01;
+
+ /* privateKey */
+ *buf ++ = 0x04;
+ buf += br_asn1_encode_length(buf, sk->xlen);
+ memcpy(buf, sk->x, sk->xlen);
+ buf += sk->xlen;
+
+ /* parameters */
+ if (include_curve_oid) {
+ *buf ++ = 0xA0;
+ *buf ++ = oid[0] + 2;
+ *buf ++ = 0x06;
+ memcpy(buf, oid, oid[0] + 1);
+ buf += oid[0] + 1;
+ }
+
+ /* publicKey */
+ if (pk != NULL) {
+ *buf ++ = 0xA1;
+ buf += br_asn1_encode_length(buf, len_publicKey_bits);
+ *buf ++ = 0x03;
+ buf += br_asn1_encode_length(buf, pk->qlen + 1);
+ *buf ++ = 0x00;
+ memcpy(buf, pk->q, pk->qlen);
+ /* buf += pk->qlen; */
+ }
+
+ return 1 + lenlen + len_seq;
+ }
+}
+
+/* see bearssl_x509.h */
+size_t
+br_encode_ec_raw_der(void *dest,
+ const br_ec_private_key *sk, const br_ec_public_key *pk)
+{
+ return br_encode_ec_raw_der_inner(dest, sk, pk, 1);
+}
diff --git a/test/monniaux/BearSSL/src/x509/encode_rsa_pk8der.c b/test/monniaux/BearSSL/src/x509/encode_rsa_pk8der.c
new file mode 100644
index 00000000..c053503d
--- /dev/null
+++ b/test/monniaux/BearSSL/src/x509/encode_rsa_pk8der.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_x509.h */
+size_t
+br_encode_rsa_pkcs8_der(void *dest, const br_rsa_private_key *sk,
+ const br_rsa_public_key *pk, const void *d, size_t dlen)
+{
+ /*
+ * ASN.1 format:
+ *
+ * OneAsymmetricKey ::= SEQUENCE {
+ * version Version,
+ * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
+ * privateKey PrivateKey,
+ * attributes [0] Attributes OPTIONAL,
+ * ...,
+ * [[2: publicKey [1] PublicKey OPTIONAL ]],
+ * ...
+ * }
+ *
+ * We don't include attributes or public key. The 'version' field
+ * is an INTEGER that we will set to 0 (meaning 'v1', compatible
+ * with previous versions of PKCS#8). The 'privateKeyAlgorithm'
+ * structure is an AlgorithmIdentifier whose OID should be
+ * rsaEncryption, with NULL parameters. The 'privateKey' is an
+ * OCTET STRING, whose value is the "raw DER" encoding of the
+ * key pair.
+ *
+ * Since the private key value comes last, this function really
+ * adds a header, which is mostly fixed (only some lengths have
+ * to be modified.
+ */
+
+ /*
+ * Concatenation of:
+ * - DER encoding of an INTEGER of value 0 (the 'version' field)
+ * - DER encoding of a PrivateKeyAlgorithmIdentifier that uses
+ * the rsaEncryption OID, and NULL parameters
+ * - An OCTET STRING tag
+ */
+ static const unsigned char PK8_HEAD[] = {
+ 0x02, 0x01, 0x00,
+ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+ 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00,
+ 0x04
+ };
+
+ size_t len_raw, len_seq;
+
+ len_raw = br_encode_rsa_raw_der(NULL, sk, pk, d, dlen);
+ len_seq = (sizeof PK8_HEAD) + len_of_len(len_raw) + len_raw;
+ if (dest == NULL) {
+ return 1 + len_of_len(len_seq) + len_seq;
+ } else {
+ unsigned char *buf;
+ size_t lenlen;
+
+ buf = dest;
+ *buf ++ = 0x30; /* SEQUENCE tag */
+ lenlen = br_asn1_encode_length(buf, len_seq);
+ buf += lenlen;
+
+ /* version, privateKeyAlgorithm, privateKey tag */
+ memcpy(buf, PK8_HEAD, sizeof PK8_HEAD);
+ buf += sizeof PK8_HEAD;
+
+ /* privateKey */
+ buf += br_asn1_encode_length(buf, len_raw);
+ br_encode_rsa_raw_der(buf, sk, pk, d, dlen);
+
+ return 1 + lenlen + len_seq;
+ }
+}
diff --git a/test/monniaux/BearSSL/src/x509/encode_rsa_rawder.c b/test/monniaux/BearSSL/src/x509/encode_rsa_rawder.c
new file mode 100644
index 00000000..1a8052b0
--- /dev/null
+++ b/test/monniaux/BearSSL/src/x509/encode_rsa_rawder.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_x509.h */
+size_t
+br_encode_rsa_raw_der(void *dest, const br_rsa_private_key *sk,
+ const br_rsa_public_key *pk, const void *d, size_t dlen)
+{
+ /*
+ * ASN.1 format:
+ *
+ * RSAPrivateKey ::= SEQUENCE {
+ * version Version,
+ * modulus INTEGER, -- n
+ * publicExponent INTEGER, -- e
+ * privateExponent INTEGER, -- d
+ * prime1 INTEGER, -- p
+ * prime2 INTEGER, -- q
+ * exponent1 INTEGER, -- d mod (p-1)
+ * exponent2 INTEGER, -- d mod (q-1)
+ * coefficient INTEGER, -- (inverse of q) mod p
+ * otherPrimeInfos OtherPrimeInfos OPTIONAL
+ * }
+ *
+ * The 'version' field is an INTEGER of value 0 (meaning: there
+ * are exactly two prime factors), and 'otherPrimeInfos' will
+ * be absent (because there are exactly two prime factors).
+ */
+
+ br_asn1_uint num[9];
+ size_t u, slen;
+
+ /*
+ * For all INTEGER values, get the pointer and length for the
+ * data bytes.
+ */
+ num[0] = br_asn1_uint_prepare(NULL, 0);
+ num[1] = br_asn1_uint_prepare(pk->n, pk->nlen);
+ num[2] = br_asn1_uint_prepare(pk->e, pk->elen);
+ num[3] = br_asn1_uint_prepare(d, dlen);
+ num[4] = br_asn1_uint_prepare(sk->p, sk->plen);
+ num[5] = br_asn1_uint_prepare(sk->q, sk->qlen);
+ num[6] = br_asn1_uint_prepare(sk->dp, sk->dplen);
+ num[7] = br_asn1_uint_prepare(sk->dq, sk->dqlen);
+ num[8] = br_asn1_uint_prepare(sk->iq, sk->iqlen);
+
+ /*
+ * Get the length of the SEQUENCE contents.
+ */
+ slen = 0;
+ for (u = 0; u < 9; u ++) {
+ uint32_t ilen;
+
+ ilen = num[u].asn1len;
+ slen += 1 + len_of_len(ilen) + ilen;
+ }
+
+ if (dest == NULL) {
+ return 1 + len_of_len(slen) + slen;
+ } else {
+ unsigned char *buf;
+ size_t lenlen;
+
+ buf = dest;
+ *buf ++ = 0x30; /* SEQUENCE tag */
+ lenlen = br_asn1_encode_length(buf, slen);
+ buf += lenlen;
+ for (u = 0; u < 9; u ++) {
+ buf += br_asn1_encode_uint(buf, num[u]);
+ }
+ return 1 + lenlen + slen;
+ }
+}
diff --git a/test/monniaux/BearSSL/src/x509/skey_decoder.c b/test/monniaux/BearSSL/src/x509/skey_decoder.c
new file mode 100644
index 00000000..f4e43e7b
--- /dev/null
+++ b/test/monniaux/BearSSL/src/x509/skey_decoder.c
@@ -0,0 +1,650 @@
+/* Automatically generated code; do not modify directly. */
+
+#include <stddef.h>
+#include <stdint.h>
+
+typedef struct {
+ uint32_t *dp;
+ uint32_t *rp;
+ const unsigned char *ip;
+} t0_context;
+
+static uint32_t
+t0_parse7E_unsigned(const unsigned char **p)
+{
+ uint32_t x;
+
+ x = 0;
+ for (;;) {
+ unsigned y;
+
+ y = *(*p) ++;
+ x = (x << 7) | (uint32_t)(y & 0x7F);
+ if (y < 0x80) {
+ return x;
+ }
+ }
+}
+
+static int32_t
+t0_parse7E_signed(const unsigned char **p)
+{
+ int neg;
+ uint32_t x;
+
+ neg = ((**p) >> 6) & 1;
+ x = (uint32_t)-neg;
+ for (;;) {
+ unsigned y;
+
+ y = *(*p) ++;
+ x = (x << 7) | (uint32_t)(y & 0x7F);
+ if (y < 0x80) {
+ if (neg) {
+ return -(int32_t)~x - 1;
+ } else {
+ return (int32_t)x;
+ }
+ }
+ }
+}
+
+#define T0_VBYTE(x, n) (unsigned char)((((uint32_t)(x) >> (n)) & 0x7F) | 0x80)
+#define T0_FBYTE(x, n) (unsigned char)(((uint32_t)(x) >> (n)) & 0x7F)
+#define T0_SBYTE(x) (unsigned char)((((uint32_t)(x) >> 28) + 0xF8) ^ 0xF8)
+#define T0_INT1(x) T0_FBYTE(x, 0)
+#define T0_INT2(x) T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+#define T0_INT3(x) T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+#define T0_INT4(x) T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+#define T0_INT5(x) T0_SBYTE(x), T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+
+/* static const unsigned char t0_datablock[]; */
+
+
+void br_skey_decoder_init_main(void *t0ctx);
+
+void br_skey_decoder_run(void *t0ctx);
+
+
+
+#include "inner.h"
+
+
+
+
+
+#include "inner.h"
+
+#define CTX ((br_skey_decoder_context *)(void *)((unsigned char *)t0ctx - offsetof(br_skey_decoder_context, cpu)))
+#define CONTEXT_NAME br_skey_decoder_context
+
+/* see bearssl_x509.h */
+void
+br_skey_decoder_init(br_skey_decoder_context *ctx)
+{
+ memset(ctx, 0, sizeof *ctx);
+ ctx->cpu.dp = &ctx->dp_stack[0];
+ ctx->cpu.rp = &ctx->rp_stack[0];
+ br_skey_decoder_init_main(&ctx->cpu);
+ br_skey_decoder_run(&ctx->cpu);
+}
+
+/* see bearssl_x509.h */
+void
+br_skey_decoder_push(br_skey_decoder_context *ctx,
+ const void *data, size_t len)
+{
+ ctx->hbuf = data;
+ ctx->hlen = len;
+ br_skey_decoder_run(&ctx->cpu);
+}
+
+
+
+static const unsigned char t0_datablock[] = {
+ 0x00, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x07,
+ 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x08, 0x2A, 0x86, 0x48, 0xCE,
+ 0x3D, 0x03, 0x01, 0x07, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x22, 0x05, 0x2B,
+ 0x81, 0x04, 0x00, 0x23
+};
+
+static const unsigned char t0_codeblock[] = {
+ 0x00, 0x01, 0x01, 0x07, 0x00, 0x00, 0x01, 0x01, 0x08, 0x00, 0x00, 0x13,
+ 0x13, 0x00, 0x00, 0x01, T0_INT1(BR_ERR_X509_BAD_TAG_CLASS), 0x00, 0x00,
+ 0x01, T0_INT1(BR_ERR_X509_BAD_TAG_VALUE), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_EXTRA_ELEMENT), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_INDEFINITE_LENGTH), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_INNER_TRUNC), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_INVALID_VALUE), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_LIMIT_EXCEEDED), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_NOT_CONSTRUCTED), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_NOT_PRIMITIVE), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_OVERFLOW), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_UNEXPECTED), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_UNSUPPORTED), 0x00, 0x00, 0x01,
+ T0_INT1(BR_KEYTYPE_EC), 0x00, 0x00, 0x01, T0_INT1(BR_KEYTYPE_RSA),
+ 0x00, 0x00, 0x01, T0_INT2(offsetof(CONTEXT_NAME, key_data)), 0x00,
+ 0x00, 0x01, T0_INT2(offsetof(CONTEXT_NAME, key_type)), 0x00, 0x00,
+ 0x33, 0x48, 0x00, 0x00, 0x01, T0_INT2(offsetof(CONTEXT_NAME, pad)),
+ 0x00, 0x00, 0x01, 0x13, 0x00, 0x00, 0x01, 0x1C, 0x00, 0x00, 0x01, 0x22,
+ 0x00, 0x00, 0x05, 0x02, 0x2C, 0x16, 0x00, 0x00, 0x06, 0x02, 0x2D, 0x16,
+ 0x00, 0x00, 0x01, 0x10, 0x3D, 0x00, 0x00, 0x0D, 0x05, 0x02, 0x2F, 0x16,
+ 0x3A, 0x00, 0x00, 0x0D, 0x05, 0x02, 0x2F, 0x16, 0x3B, 0x00, 0x00, 0x06,
+ 0x02, 0x27, 0x16, 0x00, 0x01, 0x03, 0x00, 0x54, 0x57, 0x01, 0x02, 0x3E,
+ 0x55, 0x23, 0x06, 0x02, 0x30, 0x16, 0x57, 0x01, 0x04, 0x3E, 0x02, 0x00,
+ 0x41, 0x3F, 0x00, 0x02, 0x03, 0x00, 0x53, 0x14, 0x14, 0x03, 0x01, 0x48,
+ 0x0E, 0x06, 0x02, 0x30, 0x16, 0x33, 0x4C, 0x58, 0x01, 0x7F, 0x19, 0x0D,
+ 0x06, 0x04, 0x13, 0x13, 0x04, 0x29, 0x01, 0x20, 0x19, 0x0D, 0x06, 0x16,
+ 0x13, 0x3A, 0x53, 0x4D, 0x02, 0x00, 0x06, 0x09, 0x02, 0x00, 0x0C, 0x06,
+ 0x02, 0x2A, 0x16, 0x04, 0x02, 0x03, 0x00, 0x3F, 0x04, 0x0D, 0x01, 0x21,
+ 0x19, 0x0D, 0x06, 0x04, 0x13, 0x3A, 0x04, 0x03, 0x30, 0x16, 0x13, 0x5D,
+ 0x02, 0x00, 0x05, 0x02, 0x30, 0x16, 0x02, 0x00, 0x02, 0x01, 0x1D, 0x00,
+ 0x02, 0x53, 0x4B, 0x05, 0x02, 0x30, 0x16, 0x5B, 0x15, 0x06, 0x07, 0x5D,
+ 0x01, 0x7F, 0x03, 0x01, 0x04, 0x16, 0x46, 0x15, 0x06, 0x10, 0x01, 0x00,
+ 0x03, 0x01, 0x14, 0x06, 0x03, 0x4D, 0x04, 0x02, 0x01, 0x00, 0x03, 0x00,
+ 0x04, 0x02, 0x30, 0x16, 0x3F, 0x57, 0x01, 0x04, 0x3E, 0x53, 0x02, 0x01,
+ 0x06, 0x03, 0x43, 0x04, 0x03, 0x02, 0x00, 0x40, 0x3F, 0x5D, 0x02, 0x01,
+ 0x06, 0x03, 0x32, 0x04, 0x01, 0x31, 0x00, 0x00, 0x54, 0x57, 0x01, 0x02,
+ 0x3E, 0x55, 0x06, 0x02, 0x30, 0x16, 0x57, 0x01, 0x02, 0x3E, 0x44, 0x3F,
+ 0x00, 0x07, 0x35, 0x50, 0x14, 0x05, 0x02, 0x2F, 0x16, 0x23, 0x01, 0x03,
+ 0x0B, 0x33, 0x17, 0x47, 0x07, 0x03, 0x00, 0x4F, 0x4F, 0x35, 0x4E, 0x14,
+ 0x14, 0x03, 0x01, 0x03, 0x02, 0x51, 0x14, 0x03, 0x03, 0x02, 0x02, 0x07,
+ 0x14, 0x03, 0x02, 0x51, 0x14, 0x03, 0x04, 0x02, 0x02, 0x07, 0x14, 0x03,
+ 0x02, 0x51, 0x14, 0x03, 0x05, 0x02, 0x02, 0x07, 0x14, 0x03, 0x02, 0x51,
+ 0x03, 0x06, 0x02, 0x00, 0x02, 0x01, 0x02, 0x03, 0x02, 0x04, 0x02, 0x05,
+ 0x02, 0x06, 0x1E, 0x00, 0x00, 0x19, 0x19, 0x00, 0x00, 0x01, 0x0B, 0x00,
+ 0x00, 0x01, 0x00, 0x20, 0x14, 0x06, 0x08, 0x01, 0x01, 0x21, 0x20, 0x22,
+ 0x20, 0x04, 0x75, 0x13, 0x00, 0x00, 0x01,
+ T0_INT2(3 * BR_X509_BUFSIZE_KEY), 0x00, 0x01, 0x01, 0x87, 0xFF, 0xFF,
+ 0x7F, 0x54, 0x57, 0x01, 0x02, 0x3E, 0x55, 0x01, 0x01, 0x0E, 0x06, 0x02,
+ 0x30, 0x16, 0x57, 0x01, 0x02, 0x19, 0x0D, 0x06, 0x06, 0x13, 0x3B, 0x44,
+ 0x32, 0x04, 0x1C, 0x01, 0x04, 0x19, 0x0D, 0x06, 0x08, 0x13, 0x3B, 0x01,
+ 0x00, 0x41, 0x31, 0x04, 0x0E, 0x01, 0x10, 0x19, 0x0D, 0x06, 0x05, 0x13,
+ 0x3A, 0x42, 0x04, 0x03, 0x30, 0x16, 0x13, 0x03, 0x00, 0x3F, 0x02, 0x00,
+ 0x34, 0x1F, 0x5A, 0x27, 0x16, 0x00, 0x01, 0x45, 0x0A, 0x06, 0x02, 0x29,
+ 0x16, 0x14, 0x03, 0x00, 0x08, 0x02, 0x00, 0x00, 0x00, 0x57, 0x01, 0x06,
+ 0x3E, 0x56, 0x00, 0x00, 0x20, 0x14, 0x06, 0x07, 0x1A, 0x14, 0x06, 0x01,
+ 0x12, 0x04, 0x76, 0x24, 0x00, 0x00, 0x4B, 0x05, 0x02, 0x30, 0x16, 0x37,
+ 0x15, 0x06, 0x04, 0x01, 0x17, 0x04, 0x12, 0x38, 0x15, 0x06, 0x04, 0x01,
+ 0x18, 0x04, 0x0A, 0x39, 0x15, 0x06, 0x04, 0x01, 0x19, 0x04, 0x02, 0x30,
+ 0x16, 0x00, 0x00, 0x1C, 0x57, 0x01, 0x02, 0x3E, 0x09, 0x50, 0x00, 0x00,
+ 0x35, 0x4E, 0x13, 0x00, 0x03, 0x14, 0x03, 0x00, 0x03, 0x01, 0x03, 0x02,
+ 0x53, 0x59, 0x14, 0x01, 0x81, 0x00, 0x0F, 0x06, 0x02, 0x2E, 0x16, 0x14,
+ 0x01, 0x00, 0x0D, 0x06, 0x0B, 0x13, 0x14, 0x05, 0x04, 0x13, 0x01, 0x00,
+ 0x00, 0x59, 0x04, 0x6F, 0x02, 0x01, 0x14, 0x05, 0x02, 0x2B, 0x16, 0x23,
+ 0x03, 0x01, 0x02, 0x02, 0x1F, 0x02, 0x02, 0x22, 0x03, 0x02, 0x14, 0x06,
+ 0x03, 0x59, 0x04, 0x68, 0x13, 0x02, 0x00, 0x02, 0x01, 0x08, 0x00, 0x00,
+ 0x14, 0x35, 0x1C, 0x08, 0x20, 0x1C, 0x07, 0x20, 0x4E, 0x00, 0x01, 0x59,
+ 0x14, 0x01, 0x81, 0x00, 0x0A, 0x06, 0x01, 0x00, 0x01, 0x81, 0x00, 0x08,
+ 0x14, 0x05, 0x02, 0x28, 0x16, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01,
+ 0x00, 0x0E, 0x06, 0x19, 0x02, 0x00, 0x23, 0x03, 0x00, 0x14, 0x01, 0x83,
+ 0xFF, 0xFF, 0x7F, 0x0E, 0x06, 0x02, 0x29, 0x16, 0x01, 0x08, 0x0B, 0x20,
+ 0x59, 0x1C, 0x07, 0x04, 0x60, 0x00, 0x00, 0x52, 0x4A, 0x00, 0x00, 0x57,
+ 0x3C, 0x53, 0x00, 0x01, 0x53, 0x14, 0x05, 0x02, 0x2E, 0x16, 0x59, 0x14,
+ 0x01, 0x81, 0x00, 0x0F, 0x06, 0x02, 0x2E, 0x16, 0x03, 0x00, 0x14, 0x06,
+ 0x16, 0x59, 0x02, 0x00, 0x14, 0x01, 0x87, 0xFF, 0xFF, 0x7F, 0x0F, 0x06,
+ 0x02, 0x2E, 0x16, 0x01, 0x08, 0x0B, 0x07, 0x03, 0x00, 0x04, 0x67, 0x13,
+ 0x02, 0x00, 0x00, 0x00, 0x53, 0x14, 0x01, 0x81, 0x7F, 0x0E, 0x06, 0x08,
+ 0x5C, 0x01, 0x00, 0x36, 0x1F, 0x01, 0x00, 0x00, 0x14, 0x36, 0x1F, 0x36,
+ 0x22, 0x4C, 0x01, 0x7F, 0x00, 0x01, 0x59, 0x03, 0x00, 0x02, 0x00, 0x01,
+ 0x05, 0x10, 0x01, 0x01, 0x11, 0x18, 0x02, 0x00, 0x01, 0x06, 0x10, 0x14,
+ 0x01, 0x01, 0x11, 0x06, 0x02, 0x25, 0x16, 0x01, 0x04, 0x0B, 0x02, 0x00,
+ 0x01, 0x1F, 0x11, 0x14, 0x01, 0x1F, 0x0D, 0x06, 0x02, 0x26, 0x16, 0x07,
+ 0x00, 0x00, 0x14, 0x05, 0x05, 0x01, 0x00, 0x01, 0x7F, 0x00, 0x57, 0x00,
+ 0x00, 0x14, 0x05, 0x02, 0x29, 0x16, 0x23, 0x5A, 0x00, 0x00, 0x1B, 0x14,
+ 0x01, 0x00, 0x0F, 0x06, 0x01, 0x00, 0x13, 0x12, 0x04, 0x74, 0x00, 0x01,
+ 0x01, 0x00, 0x00, 0x5D, 0x13, 0x00, 0x00, 0x14, 0x06, 0x07, 0x5E, 0x14,
+ 0x06, 0x01, 0x12, 0x04, 0x76, 0x00, 0x00, 0x01, 0x00, 0x19, 0x1A, 0x09,
+ 0x24, 0x00
+};
+
+static const uint16_t t0_caddr[] = {
+ 0,
+ 5,
+ 10,
+ 14,
+ 18,
+ 22,
+ 26,
+ 30,
+ 34,
+ 38,
+ 42,
+ 46,
+ 50,
+ 54,
+ 58,
+ 62,
+ 66,
+ 70,
+ 75,
+ 80,
+ 84,
+ 89,
+ 93,
+ 97,
+ 101,
+ 107,
+ 113,
+ 118,
+ 126,
+ 134,
+ 140,
+ 163,
+ 244,
+ 311,
+ 329,
+ 404,
+ 408,
+ 412,
+ 429,
+ 434,
+ 505,
+ 519,
+ 526,
+ 540,
+ 573,
+ 582,
+ 587,
+ 654,
+ 665,
+ 721,
+ 725,
+ 730,
+ 778,
+ 804,
+ 848,
+ 859,
+ 868,
+ 881,
+ 885,
+ 889,
+ 901
+};
+
+#define T0_INTERPRETED 34
+
+#define T0_ENTER(ip, rp, slot) do { \
+ const unsigned char *t0_newip; \
+ uint32_t t0_lnum; \
+ t0_newip = &t0_codeblock[t0_caddr[(slot) - T0_INTERPRETED]]; \
+ t0_lnum = t0_parse7E_unsigned(&t0_newip); \
+ (rp) += t0_lnum; \
+ *((rp) ++) = (uint32_t)((ip) - &t0_codeblock[0]) + (t0_lnum << 16); \
+ (ip) = t0_newip; \
+ } while (0)
+
+#define T0_DEFENTRY(name, slot) \
+void \
+name(void *ctx) \
+{ \
+ t0_context *t0ctx = ctx; \
+ t0ctx->ip = &t0_codeblock[0]; \
+ T0_ENTER(t0ctx->ip, t0ctx->rp, slot); \
+}
+
+T0_DEFENTRY(br_skey_decoder_init_main, 73)
+
+#define T0_NEXT(t0ipp) (*(*(t0ipp)) ++)
+
+void
+br_skey_decoder_run(void *t0ctx)
+{
+ uint32_t *dp, *rp;
+ const unsigned char *ip;
+
+#define T0_LOCAL(x) (*(rp - 2 - (x)))
+#define T0_POP() (*-- dp)
+#define T0_POPi() (*(int32_t *)(-- dp))
+#define T0_PEEK(x) (*(dp - 1 - (x)))
+#define T0_PEEKi(x) (*(int32_t *)(dp - 1 - (x)))
+#define T0_PUSH(v) do { *dp = (v); dp ++; } while (0)
+#define T0_PUSHi(v) do { *(int32_t *)dp = (v); dp ++; } while (0)
+#define T0_RPOP() (*-- rp)
+#define T0_RPOPi() (*(int32_t *)(-- rp))
+#define T0_RPUSH(v) do { *rp = (v); rp ++; } while (0)
+#define T0_RPUSHi(v) do { *(int32_t *)rp = (v); rp ++; } while (0)
+#define T0_ROLL(x) do { \
+ size_t t0len = (size_t)(x); \
+ uint32_t t0tmp = *(dp - 1 - t0len); \
+ memmove(dp - t0len - 1, dp - t0len, t0len * sizeof *dp); \
+ *(dp - 1) = t0tmp; \
+} while (0)
+#define T0_SWAP() do { \
+ uint32_t t0tmp = *(dp - 2); \
+ *(dp - 2) = *(dp - 1); \
+ *(dp - 1) = t0tmp; \
+} while (0)
+#define T0_ROT() do { \
+ uint32_t t0tmp = *(dp - 3); \
+ *(dp - 3) = *(dp - 2); \
+ *(dp - 2) = *(dp - 1); \
+ *(dp - 1) = t0tmp; \
+} while (0)
+#define T0_NROT() do { \
+ uint32_t t0tmp = *(dp - 1); \
+ *(dp - 1) = *(dp - 2); \
+ *(dp - 2) = *(dp - 3); \
+ *(dp - 3) = t0tmp; \
+} while (0)
+#define T0_PICK(x) do { \
+ uint32_t t0depth = (x); \
+ T0_PUSH(T0_PEEK(t0depth)); \
+} while (0)
+#define T0_CO() do { \
+ goto t0_exit; \
+} while (0)
+#define T0_RET() goto t0_next
+
+ dp = ((t0_context *)t0ctx)->dp;
+ rp = ((t0_context *)t0ctx)->rp;
+ ip = ((t0_context *)t0ctx)->ip;
+ goto t0_next;
+ for (;;) {
+ uint32_t t0x;
+
+ t0_next:
+ t0x = T0_NEXT(&ip);
+ if (t0x < T0_INTERPRETED) {
+ switch (t0x) {
+ int32_t t0off;
+
+ case 0: /* ret */
+ t0x = T0_RPOP();
+ rp -= (t0x >> 16);
+ t0x &= 0xFFFF;
+ if (t0x == 0) {
+ ip = NULL;
+ goto t0_exit;
+ }
+ ip = &t0_codeblock[t0x];
+ break;
+ case 1: /* literal constant */
+ T0_PUSHi(t0_parse7E_signed(&ip));
+ break;
+ case 2: /* read local */
+ T0_PUSH(T0_LOCAL(t0_parse7E_unsigned(&ip)));
+ break;
+ case 3: /* write local */
+ T0_LOCAL(t0_parse7E_unsigned(&ip)) = T0_POP();
+ break;
+ case 4: /* jump */
+ t0off = t0_parse7E_signed(&ip);
+ ip += t0off;
+ break;
+ case 5: /* jump if */
+ t0off = t0_parse7E_signed(&ip);
+ if (T0_POP()) {
+ ip += t0off;
+ }
+ break;
+ case 6: /* jump if not */
+ t0off = t0_parse7E_signed(&ip);
+ if (!T0_POP()) {
+ ip += t0off;
+ }
+ break;
+ case 7: {
+ /* + */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a + b);
+
+ }
+ break;
+ case 8: {
+ /* - */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a - b);
+
+ }
+ break;
+ case 9: {
+ /* -rot */
+ T0_NROT();
+ }
+ break;
+ case 10: {
+ /* < */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a < b));
+
+ }
+ break;
+ case 11: {
+ /* << */
+
+ int c = (int)T0_POPi();
+ uint32_t x = T0_POP();
+ T0_PUSH(x << c);
+
+ }
+ break;
+ case 12: {
+ /* <> */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(-(uint32_t)(a != b));
+
+ }
+ break;
+ case 13: {
+ /* = */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(-(uint32_t)(a == b));
+
+ }
+ break;
+ case 14: {
+ /* > */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a > b));
+
+ }
+ break;
+ case 15: {
+ /* >= */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a >= b));
+
+ }
+ break;
+ case 16: {
+ /* >> */
+
+ int c = (int)T0_POPi();
+ int32_t x = T0_POPi();
+ T0_PUSHi(x >> c);
+
+ }
+ break;
+ case 17: {
+ /* and */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a & b);
+
+ }
+ break;
+ case 18: {
+ /* co */
+ T0_CO();
+ }
+ break;
+ case 19: {
+ /* drop */
+ (void)T0_POP();
+ }
+ break;
+ case 20: {
+ /* dup */
+ T0_PUSH(T0_PEEK(0));
+ }
+ break;
+ case 21: {
+ /* eqOID */
+
+ const unsigned char *a2 = &t0_datablock[T0_POP()];
+ const unsigned char *a1 = &CTX->pad[0];
+ size_t len = a1[0];
+ int x;
+ if (len == a2[0]) {
+ x = -(memcmp(a1 + 1, a2 + 1, len) == 0);
+ } else {
+ x = 0;
+ }
+ T0_PUSH((uint32_t)x);
+
+ }
+ break;
+ case 22: {
+ /* fail */
+
+ CTX->err = T0_POPi();
+ T0_CO();
+
+ }
+ break;
+ case 23: {
+ /* get8 */
+
+ uint32_t addr = T0_POP();
+ T0_PUSH(*((unsigned char *)CTX + addr));
+
+ }
+ break;
+ case 24: {
+ /* neg */
+
+ uint32_t a = T0_POP();
+ T0_PUSH(-a);
+
+ }
+ break;
+ case 25: {
+ /* over */
+ T0_PUSH(T0_PEEK(1));
+ }
+ break;
+ case 26: {
+ /* read-blob-inner */
+
+ uint32_t len = T0_POP();
+ uint32_t addr = T0_POP();
+ size_t clen = CTX->hlen;
+ if (clen > len) {
+ clen = (size_t)len;
+ }
+ if (addr != 0) {
+ memcpy((unsigned char *)CTX + addr, CTX->hbuf, clen);
+ }
+ CTX->hbuf += clen;
+ CTX->hlen -= clen;
+ T0_PUSH(addr + clen);
+ T0_PUSH(len - clen);
+
+ }
+ break;
+ case 27: {
+ /* read8-low */
+
+ if (CTX->hlen == 0) {
+ T0_PUSHi(-1);
+ } else {
+ CTX->hlen --;
+ T0_PUSH(*CTX->hbuf ++);
+ }
+
+ }
+ break;
+ case 28: {
+ /* rot */
+ T0_ROT();
+ }
+ break;
+ case 29: {
+ /* set-ec-key */
+
+ size_t xlen = T0_POP();
+ uint32_t curve = T0_POP();
+ CTX->key.ec.curve = curve;
+ CTX->key.ec.x = CTX->key_data;
+ CTX->key.ec.xlen = xlen;
+
+ }
+ break;
+ case 30: {
+ /* set-rsa-key */
+
+ size_t iqlen = T0_POP();
+ size_t dqlen = T0_POP();
+ size_t dplen = T0_POP();
+ size_t qlen = T0_POP();
+ size_t plen = T0_POP();
+ uint32_t n_bitlen = T0_POP();
+ size_t off;
+
+ CTX->key.rsa.n_bitlen = n_bitlen;
+ CTX->key.rsa.p = CTX->key_data;
+ CTX->key.rsa.plen = plen;
+ off = plen;
+ CTX->key.rsa.q = CTX->key_data + off;
+ CTX->key.rsa.qlen = qlen;
+ off += qlen;
+ CTX->key.rsa.dp = CTX->key_data + off;
+ CTX->key.rsa.dplen = dplen;
+ off += dplen;
+ CTX->key.rsa.dq = CTX->key_data + off;
+ CTX->key.rsa.dqlen = dqlen;
+ off += dqlen;
+ CTX->key.rsa.iq = CTX->key_data + off;
+ CTX->key.rsa.iqlen = iqlen;
+
+ }
+ break;
+ case 31: {
+ /* set8 */
+
+ uint32_t addr = T0_POP();
+ *((unsigned char *)CTX + addr) = (unsigned char)T0_POP();
+
+ }
+ break;
+ case 32: {
+ /* swap */
+ T0_SWAP();
+ }
+ break;
+ case 33: {
+ /* u>> */
+
+ int c = (int)T0_POPi();
+ uint32_t x = T0_POP();
+ T0_PUSH(x >> c);
+
+ }
+ break;
+ }
+
+ } else {
+ T0_ENTER(ip, rp, t0x);
+ }
+ }
+t0_exit:
+ ((t0_context *)t0ctx)->dp = dp;
+ ((t0_context *)t0ctx)->rp = rp;
+ ((t0_context *)t0ctx)->ip = ip;
+}
diff --git a/test/monniaux/BearSSL/src/x509/skey_decoder.t0 b/test/monniaux/BearSSL/src/x509/skey_decoder.t0
new file mode 100644
index 00000000..5b594211
--- /dev/null
+++ b/test/monniaux/BearSSL/src/x509/skey_decoder.t0
@@ -0,0 +1,373 @@
+\ Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+\
+\ Permission is hereby granted, free of charge, to any person obtaining
+\ a copy of this software and associated documentation files (the
+\ "Software"), to deal in the Software without restriction, including
+\ without limitation the rights to use, copy, modify, merge, publish,
+\ distribute, sublicense, and/or sell copies of the Software, and to
+\ permit persons to whom the Software is furnished to do so, subject to
+\ the following conditions:
+\
+\ The above copyright notice and this permission notice shall be
+\ included in all copies or substantial portions of the Software.
+\
+\ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+\ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+\ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+\ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+\ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+\ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+\ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+\ SOFTWARE.
+
+preamble {
+
+#include "inner.h"
+
+#define CTX ((br_skey_decoder_context *)(void *)((unsigned char *)t0ctx - offsetof(br_skey_decoder_context, cpu)))
+#define CONTEXT_NAME br_skey_decoder_context
+
+/* see bearssl_x509.h */
+void
+br_skey_decoder_init(br_skey_decoder_context *ctx)
+{
+ memset(ctx, 0, sizeof *ctx);
+ ctx->cpu.dp = &ctx->dp_stack[0];
+ ctx->cpu.rp = &ctx->rp_stack[0];
+ br_skey_decoder_init_main(&ctx->cpu);
+ br_skey_decoder_run(&ctx->cpu);
+}
+
+/* see bearssl_x509.h */
+void
+br_skey_decoder_push(br_skey_decoder_context *ctx,
+ const void *data, size_t len)
+{
+ ctx->hbuf = data;
+ ctx->hlen = len;
+ br_skey_decoder_run(&ctx->cpu);
+}
+
+}
+
+addr: key_type
+addr: key_data
+
+cc: read8-low ( -- x ) {
+ if (CTX->hlen == 0) {
+ T0_PUSHi(-1);
+ } else {
+ CTX->hlen --;
+ T0_PUSH(*CTX->hbuf ++);
+ }
+}
+
+cc: read-blob-inner ( addr len -- addr len ) {
+ uint32_t len = T0_POP();
+ uint32_t addr = T0_POP();
+ size_t clen = CTX->hlen;
+ if (clen > len) {
+ clen = (size_t)len;
+ }
+ if (addr != 0) {
+ memcpy((unsigned char *)CTX + addr, CTX->hbuf, clen);
+ }
+ CTX->hbuf += clen;
+ CTX->hlen -= clen;
+ T0_PUSH(addr + clen);
+ T0_PUSH(len - clen);
+}
+
+\ Get the length of the key_data buffer.
+: len-key_data
+ CX 0 8191 { 3 * BR_X509_BUFSIZE_KEY } ;
+
+\ Get the address and length for the key_data buffer.
+: addr-len-key_data ( -- addr len )
+ addr-key_data len-key_data ;
+
+\ Set the private key (RSA).
+cc: set-rsa-key ( n_bitlen plen qlen dplen dqlen iqlen -- ) {
+ size_t iqlen = T0_POP();
+ size_t dqlen = T0_POP();
+ size_t dplen = T0_POP();
+ size_t qlen = T0_POP();
+ size_t plen = T0_POP();
+ uint32_t n_bitlen = T0_POP();
+ size_t off;
+
+ CTX->key.rsa.n_bitlen = n_bitlen;
+ CTX->key.rsa.p = CTX->key_data;
+ CTX->key.rsa.plen = plen;
+ off = plen;
+ CTX->key.rsa.q = CTX->key_data + off;
+ CTX->key.rsa.qlen = qlen;
+ off += qlen;
+ CTX->key.rsa.dp = CTX->key_data + off;
+ CTX->key.rsa.dplen = dplen;
+ off += dplen;
+ CTX->key.rsa.dq = CTX->key_data + off;
+ CTX->key.rsa.dqlen = dqlen;
+ off += dqlen;
+ CTX->key.rsa.iq = CTX->key_data + off;
+ CTX->key.rsa.iqlen = iqlen;
+}
+
+\ Set the private key (EC).
+cc: set-ec-key ( curve xlen -- ) {
+ size_t xlen = T0_POP();
+ uint32_t curve = T0_POP();
+ CTX->key.ec.curve = curve;
+ CTX->key.ec.x = CTX->key_data;
+ CTX->key.ec.xlen = xlen;
+}
+
+\ Get the bit length for an integer (unsigned).
+: int-bit-length ( x -- bitlen )
+ 0 swap
+ begin dup while 1 u>> swap 1+ swap repeat
+ drop ;
+
+\ Read an INTEGER into the key_data buffer, but then ignore it.
+: read-integer-ignore ( lim -- lim )
+ addr-len-key_data read-integer drop ;
+
+\ Read an INTEGER into the key_data buffer, at the provided offset.
+\ Returned value is the integer length (in bytes).
+: read-integer-off ( lim off -- lim dlen )
+ dup addr-len-key_data rot - swap rot + swap read-integer ;
+
+\ Decode RSA key, starting with the SEQUENCE tag.
+: decode-RSA ( lim -- lim )
+ read-sequence-open
+
+ \ Version should be 0.
+ read-tag 0x02 check-tag-primitive read-small-int-value if
+ ERR_X509_UNSUPPORTED fail
+ then
+
+ \ Read tag for the modulus; should be INTEGER. Then use the
+ \ decode-RSA-next function for the remainder of the key.
+ read-tag 0x02 check-tag-primitive
+ decode-RSA-next
+
+ \ Close the SEQUENCE.
+ close-elt ;
+
+\ Decode RSA key; the version, and the tag for the modulus, have been
+\ read.
+: decode-RSA-next ( lim -- lim )
+ \ Modulus: we read it but we do not keep it; we merely gather
+ \ the modulus bit length.
+ addr-len-key_data read-integer-next
+ dup ifnot ERR_X509_UNEXPECTED fail then
+ 1- 3 << addr-key_data get8 int-bit-length + { n_bitlen }
+
+ \ Public exponent: read but skip.
+ read-integer-ignore
+
+ \ Private exponent: read but skip.
+ read-integer-ignore
+
+ \ First prime factor.
+ addr-len-key_data read-integer dup dup { off plen }
+
+ \ Second prime factor.
+ read-integer-off dup { qlen } off + dup >off
+
+ \ First reduced private exponent.
+ read-integer-off dup { dplen } off + dup >off
+
+ \ Second reduced private exponent.
+ read-integer-off dup { dqlen } off + dup >off
+
+ \ CRT coefficient.
+ read-integer-off { iqlen }
+
+ \ Set RSA key.
+ n_bitlen plen qlen dplen dqlen iqlen set-rsa-key
+
+ \ The caller will close the sequence, thereby validating that there
+ \ is no extra field.
+ ;
+
+\ Decode an EC key, starting with the SEQUENCE tag.
+: decode-EC ( lim curve -- lim )
+ { curve }
+ read-sequence-open
+
+ \ Version should be 1.
+ read-tag 0x02 check-tag-primitive read-small-int-value 1- if
+ ERR_X509_UNSUPPORTED fail
+ then
+
+ \ Read tag for the private key; should be OCTET STRING. Then use the
+ \ decode-EC-next function for the remainder of the key.
+ read-tag 0x04 check-tag-primitive
+ curve decode-EC-next
+
+ \ Close the SEQUENCE.
+ close-elt ;
+
+\ Decode an EC key; the version, and the tag for the OCTET STRING, have
+\ already been read. The curve ID is provided (0 if unknown).
+: decode-EC-next ( lim curve -- lim )
+ { curve }
+
+ \ Read the private key proper.
+ read-length-open-elt
+ dup dup { xlen } len-key_data > if ERR_X509_UNSUPPORTED fail then
+ addr-key_data read-blob
+
+ \ Next element might be the curve identifier.
+ read-tag-or-end
+ case
+
+ \ End of structure.
+ -1 of drop endof
+
+ \ Curve parameters; we support only named curves.
+ 0x20 of
+ check-constructed read-length-open-elt
+ read-curve-ID
+ curve if
+ curve <> if ERR_X509_INVALID_VALUE fail then
+ else
+ >curve
+ then
+ close-elt
+ endof
+
+ \ Public key. We ignore it.
+ 0x21 of check-constructed endof
+
+ ERR_X509_UNSUPPORTED fail
+ endcase
+ skip-remaining
+
+ \ The curve must have been defined one way or another.
+ curve ifnot ERR_X509_UNSUPPORTED fail then
+
+ \ Set the EC key.
+ curve xlen set-ec-key
+
+ \ The caller will close the sequence.
+ ;
+
+\ Decode a PKCS#8 object. The version and the tag for the AlgorithmIdentifier
+\ structure have already been read. This function returns the key type.
+: decode-PKCS8-next ( lim -- lim keytype )
+ \ Decode the AlgorithmIdentifier.
+ read-length-open-elt
+ read-OID ifnot ERR_X509_UNSUPPORTED fail then
+ { ; is-rsa curve }
+ choice
+ rsaEncryption eqOID uf
+ \ RSA private key. We ignore the parameters.
+ skip-remaining -1 >is-rsa
+ enduf
+ id-ecPublicKey eqOID uf
+ \ EC private key. Parameters, if present, shall
+ \ identify the curve.
+ 0 >is-rsa
+ dup if read-curve-ID else 0 then >curve
+ enduf
+
+ ERR_X509_UNSUPPORTED fail
+ endchoice
+ close-elt
+
+ \ Open private key value and decode it.
+ read-tag 0x04 check-tag-primitive
+ read-length-open-elt
+ is-rsa if
+ decode-RSA
+ else
+ curve decode-EC
+ then
+ close-elt
+
+ \ We ignore any extra field, i.e. attributes or public key.
+ skip-remaining
+
+ \ Return the key type.
+ is-rsa if KEYTYPE_RSA else KEYTYPE_EC then
+ ;
+
+\ Decode a private key.
+: main ( -- ! )
+ \ RSA private key format is defined in PKCS#1 (RFC 3447):
+ \ RSAPrivateKey ::= SEQUENCE {
+ \ version INTEGER, -- 0 or 1
+ \ n INTEGER,
+ \ e INTEGER,
+ \ d INTEGER,
+ \ p INTEGER,
+ \ q INTEGER,
+ \ dp INTEGER,
+ \ dq INTEGER,
+ \ iq INTEGER,
+ \ other OtherPrimeInfos OPTIONAL
+ \ }
+ \ We do not support keys with more than two primes (these have
+ \ version 1); thus, we expect the version field to be 0, and
+ \ the 'other' field to be absent.
+ \
+ \ EC private key format is defined in RFC 5915:
+ \ ECPrivateKey ::= SEQUENCE {
+ \ version INTEGER, -- always 1
+ \ privateKey OCTET STRING,
+ \ parameters [0] EXPLICIT OBJECT IDENTIFIER OPTIONAL,
+ \ publicKey [1] EXPLICIT BIT STRING OPTIONAL
+ \ }
+ \ The "parameters" might conceptually be a complex curve description
+ \ structure but we support only named curves. The private key
+ \ contents are the unsigned big-endian encoding of the key value,
+ \ which is exactly what we want.
+ \
+ \ PKCS#8 (unencrypted) is:
+ \ OneAsymmetricKey ::= SEQUENCE {
+ \ version INTEGER, -- 0 or 1
+ \ algorithm AlgorithmIdentifier,
+ \ privateKey OCTET STRING,
+ \ attributes [0] IMPLICIT Attributes OPTIONAL,
+ \ publicKey [1] IMPLICIT BIT STRING OPTIONAL
+ \ }
+ \ The 'publicKey' field is an add-on from RFC 5958 and may be
+ \ present only if the 'version' is v2 (i.e. has value 1). We
+ \ ignore it anyway.
+
+ \ An arbitrary upper limit on the private key size.
+ 0xFFFFFF
+
+ \ Open the outer SEQUENCE.
+ read-sequence-open
+
+ \ All our schemas begin with a small INTEGER which is either 0 or
+ \ 1. We don't care which it is.
+ read-tag 0x02 check-tag-primitive read-small-int-value 1 > if
+ ERR_X509_UNSUPPORTED fail
+ then
+
+ \ Get next tag: it should be either an INTEGER (RSA private key),
+ \ an OCTET STRING (EC private key), or a SEQUENCE (for an
+ \ AlgorithmIdentifier, in a PKCS#8 object).
+ read-tag
+ case
+ 0x02 of check-primitive decode-RSA-next KEYTYPE_RSA endof
+ 0x04 of check-primitive 0 decode-EC-next KEYTYPE_EC endof
+ 0x10 of check-constructed decode-PKCS8-next endof
+ ERR_X509_UNSUPPORTED fail
+ endcase
+ { key-type }
+
+ \ Close the SEQUENCE.
+ close-elt
+
+ \ Set the key type, which marks the decoding as a success.
+ key-type addr-key_type set8
+
+ \ Read one byte, then fail: if the read succeeds, then there is
+ \ some trailing byte.
+ read8-nc ERR_X509_EXTRA_ELEMENT fail
+ ;
diff --git a/test/monniaux/BearSSL/src/x509/x509_decoder.c b/test/monniaux/BearSSL/src/x509/x509_decoder.c
new file mode 100644
index 00000000..8dd970f1
--- /dev/null
+++ b/test/monniaux/BearSSL/src/x509/x509_decoder.c
@@ -0,0 +1,773 @@
+/* Automatically generated code; do not modify directly. */
+
+#include <stddef.h>
+#include <stdint.h>
+
+typedef struct {
+ uint32_t *dp;
+ uint32_t *rp;
+ const unsigned char *ip;
+} t0_context;
+
+static uint32_t
+t0_parse7E_unsigned(const unsigned char **p)
+{
+ uint32_t x;
+
+ x = 0;
+ for (;;) {
+ unsigned y;
+
+ y = *(*p) ++;
+ x = (x << 7) | (uint32_t)(y & 0x7F);
+ if (y < 0x80) {
+ return x;
+ }
+ }
+}
+
+static int32_t
+t0_parse7E_signed(const unsigned char **p)
+{
+ int neg;
+ uint32_t x;
+
+ neg = ((**p) >> 6) & 1;
+ x = (uint32_t)-neg;
+ for (;;) {
+ unsigned y;
+
+ y = *(*p) ++;
+ x = (x << 7) | (uint32_t)(y & 0x7F);
+ if (y < 0x80) {
+ if (neg) {
+ return -(int32_t)~x - 1;
+ } else {
+ return (int32_t)x;
+ }
+ }
+ }
+}
+
+#define T0_VBYTE(x, n) (unsigned char)((((uint32_t)(x) >> (n)) & 0x7F) | 0x80)
+#define T0_FBYTE(x, n) (unsigned char)(((uint32_t)(x) >> (n)) & 0x7F)
+#define T0_SBYTE(x) (unsigned char)((((uint32_t)(x) >> 28) + 0xF8) ^ 0xF8)
+#define T0_INT1(x) T0_FBYTE(x, 0)
+#define T0_INT2(x) T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+#define T0_INT3(x) T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+#define T0_INT4(x) T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+#define T0_INT5(x) T0_SBYTE(x), T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+
+/* static const unsigned char t0_datablock[]; */
+
+
+void br_x509_decoder_init_main(void *t0ctx);
+
+void br_x509_decoder_run(void *t0ctx);
+
+
+
+#include "inner.h"
+
+
+
+
+
+#include "inner.h"
+
+#define CTX ((br_x509_decoder_context *)(void *)((unsigned char *)t0ctx - offsetof(br_x509_decoder_context, cpu)))
+#define CONTEXT_NAME br_x509_decoder_context
+
+/* see bearssl_x509.h */
+void
+br_x509_decoder_init(br_x509_decoder_context *ctx,
+ void (*append_dn)(void *ctx, const void *buf, size_t len),
+ void *append_dn_ctx)
+{
+ memset(ctx, 0, sizeof *ctx);
+ /* obsolete
+ ctx->err = 0;
+ ctx->hbuf = NULL;
+ ctx->hlen = 0;
+ */
+ ctx->append_dn = append_dn;
+ ctx->append_dn_ctx = append_dn_ctx;
+ ctx->cpu.dp = &ctx->dp_stack[0];
+ ctx->cpu.rp = &ctx->rp_stack[0];
+ br_x509_decoder_init_main(&ctx->cpu);
+ br_x509_decoder_run(&ctx->cpu);
+}
+
+/* see bearssl_x509.h */
+void
+br_x509_decoder_push(br_x509_decoder_context *ctx,
+ const void *data, size_t len)
+{
+ ctx->hbuf = data;
+ ctx->hlen = len;
+ br_x509_decoder_run(&ctx->cpu);
+}
+
+
+
+static const unsigned char t0_datablock[] = {
+ 0x00, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x09,
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x05, 0x09, 0x2A, 0x86,
+ 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0E, 0x09, 0x2A, 0x86, 0x48, 0x86,
+ 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D,
+ 0x01, 0x01, 0x0C, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01,
+ 0x0D, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x08, 0x2A, 0x86,
+ 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x22,
+ 0x05, 0x2B, 0x81, 0x04, 0x00, 0x23, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D,
+ 0x04, 0x01, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x01, 0x08,
+ 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02, 0x08, 0x2A, 0x86, 0x48,
+ 0xCE, 0x3D, 0x04, 0x03, 0x03, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04,
+ 0x03, 0x04, 0x00, 0x1F, 0x03, 0xFC, 0x07, 0x7F, 0x0B, 0x5E, 0x0F, 0x1F,
+ 0x12, 0xFE, 0x16, 0xBF, 0x1A, 0x9F, 0x1E, 0x7E, 0x22, 0x3F, 0x26, 0x1E,
+ 0x29, 0xDF, 0x00, 0x1F, 0x03, 0xFD, 0x07, 0x9F, 0x0B, 0x7E, 0x0F, 0x3F,
+ 0x13, 0x1E, 0x16, 0xDF, 0x1A, 0xBF, 0x1E, 0x9E, 0x22, 0x5F, 0x26, 0x3E,
+ 0x29, 0xFF, 0x03, 0x55, 0x1D, 0x13
+};
+
+static const unsigned char t0_codeblock[] = {
+ 0x00, 0x01, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x11, 0x00, 0x00, 0x01,
+ 0x01, 0x09, 0x00, 0x00, 0x01, 0x01, 0x0A, 0x00, 0x00, 0x1A, 0x1A, 0x00,
+ 0x00, 0x01, T0_INT1(BR_ERR_X509_BAD_BOOLEAN), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_BAD_TAG_CLASS), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_BAD_TAG_VALUE), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_BAD_TIME), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_EXTRA_ELEMENT), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_INDEFINITE_LENGTH), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_INNER_TRUNC), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_LIMIT_EXCEEDED), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_NOT_CONSTRUCTED), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_NOT_PRIMITIVE), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_OVERFLOW), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_PARTIAL_BYTE), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_UNEXPECTED), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_UNSUPPORTED), 0x00, 0x00, 0x01,
+ T0_INT1(BR_KEYTYPE_EC), 0x00, 0x00, 0x01, T0_INT1(BR_KEYTYPE_RSA),
+ 0x00, 0x00, 0x01, T0_INT2(offsetof(CONTEXT_NAME, copy_dn)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(CONTEXT_NAME, decoded)), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(CONTEXT_NAME, isCA)), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_x509_decoder_context, pkey_data)), 0x01,
+ T0_INT2(BR_X509_BUFSIZE_KEY), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(CONTEXT_NAME, notafter_days)), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(CONTEXT_NAME, notafter_seconds)), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(CONTEXT_NAME, notbefore_days)), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(CONTEXT_NAME, notbefore_seconds)), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(CONTEXT_NAME, pad)), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(CONTEXT_NAME, signer_hash_id)), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(CONTEXT_NAME, signer_key_type)), 0x00, 0x00, 0x01,
+ 0x80, 0x45, 0x00, 0x00, 0x01, 0x80, 0x4E, 0x00, 0x00, 0x01, 0x80, 0x54,
+ 0x00, 0x00, 0x01, 0x81, 0x36, 0x00, 0x02, 0x03, 0x00, 0x03, 0x01, 0x1B,
+ 0x02, 0x01, 0x13, 0x26, 0x02, 0x00, 0x0F, 0x15, 0x00, 0x00, 0x05, 0x02,
+ 0x34, 0x1D, 0x00, 0x00, 0x06, 0x02, 0x35, 0x1D, 0x00, 0x00, 0x01, 0x10,
+ 0x4F, 0x00, 0x00, 0x11, 0x05, 0x02, 0x38, 0x1D, 0x4C, 0x00, 0x00, 0x11,
+ 0x05, 0x02, 0x38, 0x1D, 0x4D, 0x00, 0x00, 0x06, 0x02, 0x30, 0x1D, 0x00,
+ 0x00, 0x1B, 0x19, 0x01, 0x08, 0x0E, 0x26, 0x29, 0x19, 0x09, 0x00, 0x00,
+ 0x01, 0x30, 0x0A, 0x1B, 0x01, 0x00, 0x01, 0x09, 0x4B, 0x05, 0x02, 0x2F,
+ 0x1D, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, 0x01, 0x80, 0x5A, 0x00, 0x00,
+ 0x01, 0x80, 0x62, 0x00, 0x00, 0x01, 0x80, 0x6B, 0x00, 0x00, 0x01, 0x80,
+ 0x74, 0x00, 0x00, 0x01, 0x80, 0x7D, 0x00, 0x00, 0x01, 0x3D, 0x00, 0x00,
+ 0x20, 0x11, 0x06, 0x04, 0x2B, 0x6B, 0x7A, 0x71, 0x00, 0x04, 0x01, 0x00,
+ 0x3D, 0x25, 0x01, 0x00, 0x3C, 0x25, 0x01, 0x87, 0xFF, 0xFF, 0x7F, 0x6D,
+ 0x6D, 0x70, 0x1B, 0x01, 0x20, 0x11, 0x06, 0x11, 0x1A, 0x4C, 0x6B, 0x70,
+ 0x01, 0x02, 0x50, 0x6E, 0x01, 0x02, 0x12, 0x06, 0x02, 0x39, 0x1D, 0x51,
+ 0x70, 0x01, 0x02, 0x50, 0x6C, 0x6D, 0x7A, 0x6D, 0x7A, 0x6D, 0x65, 0x43,
+ 0x24, 0x42, 0x24, 0x65, 0x41, 0x24, 0x40, 0x24, 0x51, 0x01, 0x01, 0x3C,
+ 0x25, 0x6D, 0x7A, 0x01, 0x00, 0x3C, 0x25, 0x6D, 0x6D, 0x60, 0x05, 0x02,
+ 0x39, 0x1D, 0x74, 0x1C, 0x06, 0x1C, 0x7A, 0x61, 0x6D, 0x3F, 0x68, 0x03,
+ 0x00, 0x3F, 0x26, 0x02, 0x00, 0x09, 0x26, 0x02, 0x00, 0x0A, 0x68, 0x03,
+ 0x01, 0x51, 0x51, 0x02, 0x00, 0x02, 0x01, 0x18, 0x04, 0x1E, 0x5A, 0x1C,
+ 0x06, 0x18, 0x64, 0x03, 0x02, 0x51, 0x61, 0x1B, 0x03, 0x03, 0x1B, 0x3F,
+ 0x23, 0x0D, 0x06, 0x02, 0x33, 0x1D, 0x62, 0x02, 0x02, 0x02, 0x03, 0x17,
+ 0x04, 0x02, 0x39, 0x1D, 0x51, 0x01, 0x00, 0x3E, 0x25, 0x71, 0x01, 0x21,
+ 0x5B, 0x01, 0x22, 0x5B, 0x1B, 0x01, 0x23, 0x11, 0x06, 0x28, 0x1A, 0x4C,
+ 0x6B, 0x6D, 0x1B, 0x06, 0x1D, 0x6D, 0x60, 0x1A, 0x70, 0x1B, 0x01, 0x01,
+ 0x11, 0x06, 0x03, 0x63, 0x1A, 0x70, 0x01, 0x04, 0x50, 0x6B, 0x4A, 0x1C,
+ 0x06, 0x03, 0x5F, 0x04, 0x01, 0x7B, 0x51, 0x51, 0x04, 0x60, 0x51, 0x51,
+ 0x04, 0x08, 0x01, 0x7F, 0x11, 0x05, 0x02, 0x38, 0x1D, 0x1A, 0x51, 0x6D,
+ 0x60, 0x06, 0x80, 0x63, 0x75, 0x1C, 0x06, 0x06, 0x01, 0x02, 0x3B, 0x04,
+ 0x80, 0x57, 0x76, 0x1C, 0x06, 0x06, 0x01, 0x03, 0x3B, 0x04, 0x80, 0x4D,
+ 0x77, 0x1C, 0x06, 0x06, 0x01, 0x04, 0x3B, 0x04, 0x80, 0x43, 0x78, 0x1C,
+ 0x06, 0x05, 0x01, 0x05, 0x3B, 0x04, 0x3A, 0x79, 0x1C, 0x06, 0x05, 0x01,
+ 0x06, 0x3B, 0x04, 0x31, 0x55, 0x1C, 0x06, 0x05, 0x01, 0x02, 0x3A, 0x04,
+ 0x28, 0x56, 0x1C, 0x06, 0x05, 0x01, 0x03, 0x3A, 0x04, 0x1F, 0x57, 0x1C,
+ 0x06, 0x05, 0x01, 0x04, 0x3A, 0x04, 0x16, 0x58, 0x1C, 0x06, 0x05, 0x01,
+ 0x05, 0x3A, 0x04, 0x0D, 0x59, 0x1C, 0x06, 0x05, 0x01, 0x06, 0x3A, 0x04,
+ 0x04, 0x01, 0x00, 0x01, 0x00, 0x04, 0x04, 0x01, 0x00, 0x01, 0x00, 0x46,
+ 0x25, 0x45, 0x25, 0x7A, 0x61, 0x7A, 0x51, 0x1A, 0x01, 0x01, 0x3D, 0x25,
+ 0x73, 0x30, 0x1D, 0x00, 0x00, 0x01, 0x81, 0x06, 0x00, 0x01, 0x54, 0x0D,
+ 0x06, 0x02, 0x32, 0x1D, 0x1B, 0x03, 0x00, 0x0A, 0x02, 0x00, 0x00, 0x00,
+ 0x6D, 0x71, 0x1B, 0x01, 0x01, 0x11, 0x06, 0x08, 0x63, 0x01, 0x01, 0x15,
+ 0x3E, 0x25, 0x04, 0x01, 0x2B, 0x7A, 0x00, 0x00, 0x70, 0x01, 0x06, 0x50,
+ 0x6F, 0x00, 0x00, 0x70, 0x01, 0x03, 0x50, 0x6B, 0x72, 0x06, 0x02, 0x37,
+ 0x1D, 0x00, 0x00, 0x26, 0x1B, 0x06, 0x07, 0x21, 0x1B, 0x06, 0x01, 0x16,
+ 0x04, 0x76, 0x2B, 0x00, 0x00, 0x01, 0x01, 0x50, 0x6A, 0x01, 0x01, 0x10,
+ 0x06, 0x02, 0x2C, 0x1D, 0x72, 0x27, 0x00, 0x00, 0x60, 0x05, 0x02, 0x39,
+ 0x1D, 0x47, 0x1C, 0x06, 0x04, 0x01, 0x17, 0x04, 0x12, 0x48, 0x1C, 0x06,
+ 0x04, 0x01, 0x18, 0x04, 0x0A, 0x49, 0x1C, 0x06, 0x04, 0x01, 0x19, 0x04,
+ 0x02, 0x39, 0x1D, 0x00, 0x04, 0x70, 0x1B, 0x01, 0x17, 0x01, 0x18, 0x4B,
+ 0x05, 0x02, 0x2F, 0x1D, 0x01, 0x18, 0x11, 0x03, 0x00, 0x4D, 0x6B, 0x66,
+ 0x02, 0x00, 0x06, 0x0C, 0x01, 0x80, 0x64, 0x08, 0x03, 0x01, 0x66, 0x02,
+ 0x01, 0x09, 0x04, 0x0E, 0x1B, 0x01, 0x32, 0x0D, 0x06, 0x04, 0x01, 0x80,
+ 0x64, 0x09, 0x01, 0x8E, 0x6C, 0x09, 0x03, 0x01, 0x02, 0x01, 0x01, 0x82,
+ 0x6D, 0x08, 0x02, 0x01, 0x01, 0x03, 0x09, 0x01, 0x04, 0x0C, 0x09, 0x02,
+ 0x01, 0x01, 0x80, 0x63, 0x09, 0x01, 0x80, 0x64, 0x0C, 0x0A, 0x02, 0x01,
+ 0x01, 0x83, 0x0F, 0x09, 0x01, 0x83, 0x10, 0x0C, 0x09, 0x03, 0x03, 0x01,
+ 0x01, 0x01, 0x0C, 0x67, 0x2A, 0x01, 0x01, 0x0E, 0x02, 0x01, 0x01, 0x04,
+ 0x07, 0x28, 0x02, 0x01, 0x01, 0x80, 0x64, 0x07, 0x27, 0x02, 0x01, 0x01,
+ 0x83, 0x10, 0x07, 0x28, 0x1F, 0x15, 0x06, 0x03, 0x01, 0x18, 0x09, 0x5D,
+ 0x09, 0x52, 0x1B, 0x01, 0x05, 0x14, 0x02, 0x03, 0x09, 0x03, 0x03, 0x01,
+ 0x1F, 0x15, 0x01, 0x01, 0x26, 0x67, 0x02, 0x03, 0x09, 0x2A, 0x03, 0x03,
+ 0x01, 0x00, 0x01, 0x17, 0x67, 0x01, 0x9C, 0x10, 0x08, 0x03, 0x02, 0x01,
+ 0x00, 0x01, 0x3B, 0x67, 0x01, 0x3C, 0x08, 0x02, 0x02, 0x09, 0x03, 0x02,
+ 0x01, 0x00, 0x01, 0x3C, 0x67, 0x02, 0x02, 0x09, 0x03, 0x02, 0x72, 0x1B,
+ 0x01, 0x2E, 0x11, 0x06, 0x0D, 0x1A, 0x72, 0x1B, 0x01, 0x30, 0x01, 0x39,
+ 0x4B, 0x06, 0x03, 0x1A, 0x04, 0x74, 0x01, 0x80, 0x5A, 0x10, 0x06, 0x02,
+ 0x2F, 0x1D, 0x51, 0x02, 0x03, 0x02, 0x02, 0x00, 0x01, 0x72, 0x53, 0x01,
+ 0x0A, 0x08, 0x03, 0x00, 0x72, 0x53, 0x02, 0x00, 0x09, 0x00, 0x02, 0x03,
+ 0x00, 0x03, 0x01, 0x66, 0x1B, 0x02, 0x01, 0x02, 0x00, 0x4B, 0x05, 0x02,
+ 0x2F, 0x1D, 0x00, 0x00, 0x23, 0x70, 0x01, 0x02, 0x50, 0x0B, 0x69, 0x00,
+ 0x03, 0x1B, 0x03, 0x00, 0x03, 0x01, 0x03, 0x02, 0x6B, 0x72, 0x1B, 0x01,
+ 0x81, 0x00, 0x13, 0x06, 0x02, 0x36, 0x1D, 0x1B, 0x01, 0x00, 0x11, 0x06,
+ 0x0B, 0x1A, 0x1B, 0x05, 0x04, 0x1A, 0x01, 0x00, 0x00, 0x72, 0x04, 0x6F,
+ 0x02, 0x01, 0x1B, 0x05, 0x02, 0x33, 0x1D, 0x2A, 0x03, 0x01, 0x02, 0x02,
+ 0x25, 0x02, 0x02, 0x29, 0x03, 0x02, 0x1B, 0x06, 0x03, 0x72, 0x04, 0x68,
+ 0x1A, 0x02, 0x00, 0x02, 0x01, 0x0A, 0x00, 0x01, 0x72, 0x1B, 0x01, 0x81,
+ 0x00, 0x0D, 0x06, 0x01, 0x00, 0x01, 0x81, 0x00, 0x0A, 0x1B, 0x05, 0x02,
+ 0x31, 0x1D, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x12, 0x06,
+ 0x19, 0x02, 0x00, 0x2A, 0x03, 0x00, 0x1B, 0x01, 0x83, 0xFF, 0xFF, 0x7F,
+ 0x12, 0x06, 0x02, 0x32, 0x1D, 0x01, 0x08, 0x0E, 0x26, 0x72, 0x23, 0x09,
+ 0x04, 0x60, 0x00, 0x00, 0x6A, 0x5E, 0x00, 0x00, 0x6B, 0x7A, 0x00, 0x00,
+ 0x70, 0x4E, 0x6B, 0x00, 0x01, 0x6B, 0x1B, 0x05, 0x02, 0x36, 0x1D, 0x72,
+ 0x1B, 0x01, 0x81, 0x00, 0x13, 0x06, 0x02, 0x36, 0x1D, 0x03, 0x00, 0x1B,
+ 0x06, 0x16, 0x72, 0x02, 0x00, 0x1B, 0x01, 0x87, 0xFF, 0xFF, 0x7F, 0x13,
+ 0x06, 0x02, 0x36, 0x1D, 0x01, 0x08, 0x0E, 0x09, 0x03, 0x00, 0x04, 0x67,
+ 0x1A, 0x02, 0x00, 0x00, 0x00, 0x6B, 0x1B, 0x01, 0x81, 0x7F, 0x12, 0x06,
+ 0x08, 0x7A, 0x01, 0x00, 0x44, 0x25, 0x01, 0x00, 0x00, 0x1B, 0x44, 0x25,
+ 0x44, 0x29, 0x62, 0x01, 0x7F, 0x00, 0x01, 0x72, 0x03, 0x00, 0x02, 0x00,
+ 0x01, 0x05, 0x14, 0x01, 0x01, 0x15, 0x1E, 0x02, 0x00, 0x01, 0x06, 0x14,
+ 0x1B, 0x01, 0x01, 0x15, 0x06, 0x02, 0x2D, 0x1D, 0x01, 0x04, 0x0E, 0x02,
+ 0x00, 0x01, 0x1F, 0x15, 0x1B, 0x01, 0x1F, 0x11, 0x06, 0x02, 0x2E, 0x1D,
+ 0x09, 0x00, 0x00, 0x1B, 0x05, 0x05, 0x01, 0x00, 0x01, 0x7F, 0x00, 0x70,
+ 0x00, 0x00, 0x1B, 0x05, 0x02, 0x32, 0x1D, 0x2A, 0x73, 0x00, 0x00, 0x22,
+ 0x1B, 0x01, 0x00, 0x13, 0x06, 0x01, 0x00, 0x1A, 0x16, 0x04, 0x74, 0x00,
+ 0x01, 0x01, 0x00, 0x00, 0x01, 0x0B, 0x00, 0x00, 0x01, 0x15, 0x00, 0x00,
+ 0x01, 0x1F, 0x00, 0x00, 0x01, 0x29, 0x00, 0x00, 0x01, 0x33, 0x00, 0x00,
+ 0x7B, 0x1A, 0x00, 0x00, 0x1B, 0x06, 0x07, 0x7C, 0x1B, 0x06, 0x01, 0x16,
+ 0x04, 0x76, 0x00, 0x00, 0x01, 0x00, 0x20, 0x21, 0x0B, 0x2B, 0x00
+};
+
+static const uint16_t t0_caddr[] = {
+ 0,
+ 5,
+ 10,
+ 15,
+ 20,
+ 24,
+ 28,
+ 32,
+ 36,
+ 40,
+ 44,
+ 48,
+ 52,
+ 56,
+ 60,
+ 64,
+ 68,
+ 72,
+ 76,
+ 80,
+ 84,
+ 88,
+ 93,
+ 98,
+ 103,
+ 111,
+ 116,
+ 121,
+ 126,
+ 131,
+ 136,
+ 141,
+ 146,
+ 151,
+ 156,
+ 161,
+ 166,
+ 181,
+ 187,
+ 193,
+ 198,
+ 206,
+ 214,
+ 220,
+ 231,
+ 246,
+ 250,
+ 255,
+ 260,
+ 265,
+ 270,
+ 275,
+ 279,
+ 289,
+ 620,
+ 625,
+ 639,
+ 659,
+ 666,
+ 678,
+ 692,
+ 707,
+ 740,
+ 960,
+ 974,
+ 991,
+ 1000,
+ 1067,
+ 1123,
+ 1127,
+ 1131,
+ 1136,
+ 1184,
+ 1210,
+ 1254,
+ 1265,
+ 1274,
+ 1287,
+ 1291,
+ 1295,
+ 1299,
+ 1303,
+ 1307,
+ 1311,
+ 1315,
+ 1327
+};
+
+#define T0_INTERPRETED 39
+
+#define T0_ENTER(ip, rp, slot) do { \
+ const unsigned char *t0_newip; \
+ uint32_t t0_lnum; \
+ t0_newip = &t0_codeblock[t0_caddr[(slot) - T0_INTERPRETED]]; \
+ t0_lnum = t0_parse7E_unsigned(&t0_newip); \
+ (rp) += t0_lnum; \
+ *((rp) ++) = (uint32_t)((ip) - &t0_codeblock[0]) + (t0_lnum << 16); \
+ (ip) = t0_newip; \
+ } while (0)
+
+#define T0_DEFENTRY(name, slot) \
+void \
+name(void *ctx) \
+{ \
+ t0_context *t0ctx = ctx; \
+ t0ctx->ip = &t0_codeblock[0]; \
+ T0_ENTER(t0ctx->ip, t0ctx->rp, slot); \
+}
+
+T0_DEFENTRY(br_x509_decoder_init_main, 92)
+
+#define T0_NEXT(t0ipp) (*(*(t0ipp)) ++)
+
+void
+br_x509_decoder_run(void *t0ctx)
+{
+ uint32_t *dp, *rp;
+ const unsigned char *ip;
+
+#define T0_LOCAL(x) (*(rp - 2 - (x)))
+#define T0_POP() (*-- dp)
+#define T0_POPi() (*(int32_t *)(-- dp))
+#define T0_PEEK(x) (*(dp - 1 - (x)))
+#define T0_PEEKi(x) (*(int32_t *)(dp - 1 - (x)))
+#define T0_PUSH(v) do { *dp = (v); dp ++; } while (0)
+#define T0_PUSHi(v) do { *(int32_t *)dp = (v); dp ++; } while (0)
+#define T0_RPOP() (*-- rp)
+#define T0_RPOPi() (*(int32_t *)(-- rp))
+#define T0_RPUSH(v) do { *rp = (v); rp ++; } while (0)
+#define T0_RPUSHi(v) do { *(int32_t *)rp = (v); rp ++; } while (0)
+#define T0_ROLL(x) do { \
+ size_t t0len = (size_t)(x); \
+ uint32_t t0tmp = *(dp - 1 - t0len); \
+ memmove(dp - t0len - 1, dp - t0len, t0len * sizeof *dp); \
+ *(dp - 1) = t0tmp; \
+} while (0)
+#define T0_SWAP() do { \
+ uint32_t t0tmp = *(dp - 2); \
+ *(dp - 2) = *(dp - 1); \
+ *(dp - 1) = t0tmp; \
+} while (0)
+#define T0_ROT() do { \
+ uint32_t t0tmp = *(dp - 3); \
+ *(dp - 3) = *(dp - 2); \
+ *(dp - 2) = *(dp - 1); \
+ *(dp - 1) = t0tmp; \
+} while (0)
+#define T0_NROT() do { \
+ uint32_t t0tmp = *(dp - 1); \
+ *(dp - 1) = *(dp - 2); \
+ *(dp - 2) = *(dp - 3); \
+ *(dp - 3) = t0tmp; \
+} while (0)
+#define T0_PICK(x) do { \
+ uint32_t t0depth = (x); \
+ T0_PUSH(T0_PEEK(t0depth)); \
+} while (0)
+#define T0_CO() do { \
+ goto t0_exit; \
+} while (0)
+#define T0_RET() goto t0_next
+
+ dp = ((t0_context *)t0ctx)->dp;
+ rp = ((t0_context *)t0ctx)->rp;
+ ip = ((t0_context *)t0ctx)->ip;
+ goto t0_next;
+ for (;;) {
+ uint32_t t0x;
+
+ t0_next:
+ t0x = T0_NEXT(&ip);
+ if (t0x < T0_INTERPRETED) {
+ switch (t0x) {
+ int32_t t0off;
+
+ case 0: /* ret */
+ t0x = T0_RPOP();
+ rp -= (t0x >> 16);
+ t0x &= 0xFFFF;
+ if (t0x == 0) {
+ ip = NULL;
+ goto t0_exit;
+ }
+ ip = &t0_codeblock[t0x];
+ break;
+ case 1: /* literal constant */
+ T0_PUSHi(t0_parse7E_signed(&ip));
+ break;
+ case 2: /* read local */
+ T0_PUSH(T0_LOCAL(t0_parse7E_unsigned(&ip)));
+ break;
+ case 3: /* write local */
+ T0_LOCAL(t0_parse7E_unsigned(&ip)) = T0_POP();
+ break;
+ case 4: /* jump */
+ t0off = t0_parse7E_signed(&ip);
+ ip += t0off;
+ break;
+ case 5: /* jump if */
+ t0off = t0_parse7E_signed(&ip);
+ if (T0_POP()) {
+ ip += t0off;
+ }
+ break;
+ case 6: /* jump if not */
+ t0off = t0_parse7E_signed(&ip);
+ if (!T0_POP()) {
+ ip += t0off;
+ }
+ break;
+ case 7: {
+ /* %25 */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSHi(a % b);
+
+ }
+ break;
+ case 8: {
+ /* * */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a * b);
+
+ }
+ break;
+ case 9: {
+ /* + */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a + b);
+
+ }
+ break;
+ case 10: {
+ /* - */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a - b);
+
+ }
+ break;
+ case 11: {
+ /* -rot */
+ T0_NROT();
+ }
+ break;
+ case 12: {
+ /* / */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSHi(a / b);
+
+ }
+ break;
+ case 13: {
+ /* < */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a < b));
+
+ }
+ break;
+ case 14: {
+ /* << */
+
+ int c = (int)T0_POPi();
+ uint32_t x = T0_POP();
+ T0_PUSH(x << c);
+
+ }
+ break;
+ case 15: {
+ /* <= */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a <= b));
+
+ }
+ break;
+ case 16: {
+ /* <> */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(-(uint32_t)(a != b));
+
+ }
+ break;
+ case 17: {
+ /* = */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(-(uint32_t)(a == b));
+
+ }
+ break;
+ case 18: {
+ /* > */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a > b));
+
+ }
+ break;
+ case 19: {
+ /* >= */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a >= b));
+
+ }
+ break;
+ case 20: {
+ /* >> */
+
+ int c = (int)T0_POPi();
+ int32_t x = T0_POPi();
+ T0_PUSHi(x >> c);
+
+ }
+ break;
+ case 21: {
+ /* and */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a & b);
+
+ }
+ break;
+ case 22: {
+ /* co */
+ T0_CO();
+ }
+ break;
+ case 23: {
+ /* copy-ec-pkey */
+
+ size_t qlen = T0_POP();
+ uint32_t curve = T0_POP();
+ CTX->pkey.key_type = BR_KEYTYPE_EC;
+ CTX->pkey.key.ec.curve = curve;
+ CTX->pkey.key.ec.q = CTX->pkey_data;
+ CTX->pkey.key.ec.qlen = qlen;
+
+ }
+ break;
+ case 24: {
+ /* copy-rsa-pkey */
+
+ size_t elen = T0_POP();
+ size_t nlen = T0_POP();
+ CTX->pkey.key_type = BR_KEYTYPE_RSA;
+ CTX->pkey.key.rsa.n = CTX->pkey_data;
+ CTX->pkey.key.rsa.nlen = nlen;
+ CTX->pkey.key.rsa.e = CTX->pkey_data + nlen;
+ CTX->pkey.key.rsa.elen = elen;
+
+ }
+ break;
+ case 25: {
+ /* data-get8 */
+
+ size_t addr = T0_POP();
+ T0_PUSH(t0_datablock[addr]);
+
+ }
+ break;
+ case 26: {
+ /* drop */
+ (void)T0_POP();
+ }
+ break;
+ case 27: {
+ /* dup */
+ T0_PUSH(T0_PEEK(0));
+ }
+ break;
+ case 28: {
+ /* eqOID */
+
+ const unsigned char *a2 = &t0_datablock[T0_POP()];
+ const unsigned char *a1 = &CTX->pad[0];
+ size_t len = a1[0];
+ int x;
+ if (len == a2[0]) {
+ x = -(memcmp(a1 + 1, a2 + 1, len) == 0);
+ } else {
+ x = 0;
+ }
+ T0_PUSH((uint32_t)x);
+
+ }
+ break;
+ case 29: {
+ /* fail */
+
+ CTX->err = T0_POPi();
+ T0_CO();
+
+ }
+ break;
+ case 30: {
+ /* neg */
+
+ uint32_t a = T0_POP();
+ T0_PUSH(-a);
+
+ }
+ break;
+ case 31: {
+ /* or */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a | b);
+
+ }
+ break;
+ case 32: {
+ /* over */
+ T0_PUSH(T0_PEEK(1));
+ }
+ break;
+ case 33: {
+ /* read-blob-inner */
+
+ uint32_t len = T0_POP();
+ uint32_t addr = T0_POP();
+ size_t clen = CTX->hlen;
+ if (clen > len) {
+ clen = (size_t)len;
+ }
+ if (addr != 0) {
+ memcpy((unsigned char *)CTX + addr, CTX->hbuf, clen);
+ }
+ if (CTX->copy_dn && CTX->append_dn) {
+ CTX->append_dn(CTX->append_dn_ctx, CTX->hbuf, clen);
+ }
+ CTX->hbuf += clen;
+ CTX->hlen -= clen;
+ T0_PUSH(addr + clen);
+ T0_PUSH(len - clen);
+
+ }
+ break;
+ case 34: {
+ /* read8-low */
+
+ if (CTX->hlen == 0) {
+ T0_PUSHi(-1);
+ } else {
+ unsigned char x = *CTX->hbuf ++;
+ if (CTX->copy_dn && CTX->append_dn) {
+ CTX->append_dn(CTX->append_dn_ctx, &x, 1);
+ }
+ CTX->hlen --;
+ T0_PUSH(x);
+ }
+
+ }
+ break;
+ case 35: {
+ /* rot */
+ T0_ROT();
+ }
+ break;
+ case 36: {
+ /* set32 */
+
+ uint32_t addr = T0_POP();
+ *(uint32_t *)(void *)((unsigned char *)CTX + addr) = T0_POP();
+
+ }
+ break;
+ case 37: {
+ /* set8 */
+
+ uint32_t addr = T0_POP();
+ *((unsigned char *)CTX + addr) = (unsigned char)T0_POP();
+
+ }
+ break;
+ case 38: {
+ /* swap */
+ T0_SWAP();
+ }
+ break;
+ }
+
+ } else {
+ T0_ENTER(ip, rp, t0x);
+ }
+ }
+t0_exit:
+ ((t0_context *)t0ctx)->dp = dp;
+ ((t0_context *)t0ctx)->rp = rp;
+ ((t0_context *)t0ctx)->ip = ip;
+}
diff --git a/test/monniaux/BearSSL/src/x509/x509_decoder.t0 b/test/monniaux/BearSSL/src/x509/x509_decoder.t0
new file mode 100644
index 00000000..0bf276fb
--- /dev/null
+++ b/test/monniaux/BearSSL/src/x509/x509_decoder.t0
@@ -0,0 +1,321 @@
+\ Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+\
+\ Permission is hereby granted, free of charge, to any person obtaining
+\ a copy of this software and associated documentation files (the
+\ "Software"), to deal in the Software without restriction, including
+\ without limitation the rights to use, copy, modify, merge, publish,
+\ distribute, sublicense, and/or sell copies of the Software, and to
+\ permit persons to whom the Software is furnished to do so, subject to
+\ the following conditions:
+\
+\ The above copyright notice and this permission notice shall be
+\ included in all copies or substantial portions of the Software.
+\
+\ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+\ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+\ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+\ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+\ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+\ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+\ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+\ SOFTWARE.
+
+preamble {
+
+#include "inner.h"
+
+#define CTX ((br_x509_decoder_context *)(void *)((unsigned char *)t0ctx - offsetof(br_x509_decoder_context, cpu)))
+#define CONTEXT_NAME br_x509_decoder_context
+
+/* see bearssl_x509.h */
+void
+br_x509_decoder_init(br_x509_decoder_context *ctx,
+ void (*append_dn)(void *ctx, const void *buf, size_t len),
+ void *append_dn_ctx)
+{
+ memset(ctx, 0, sizeof *ctx);
+ /* obsolete
+ ctx->err = 0;
+ ctx->hbuf = NULL;
+ ctx->hlen = 0;
+ */
+ ctx->append_dn = append_dn;
+ ctx->append_dn_ctx = append_dn_ctx;
+ ctx->cpu.dp = &ctx->dp_stack[0];
+ ctx->cpu.rp = &ctx->rp_stack[0];
+ br_x509_decoder_init_main(&ctx->cpu);
+ br_x509_decoder_run(&ctx->cpu);
+}
+
+/* see bearssl_x509.h */
+void
+br_x509_decoder_push(br_x509_decoder_context *ctx,
+ const void *data, size_t len)
+{
+ ctx->hbuf = data;
+ ctx->hlen = len;
+ br_x509_decoder_run(&ctx->cpu);
+}
+
+}
+
+addr: decoded
+addr: notbefore_days
+addr: notbefore_seconds
+addr: notafter_days
+addr: notafter_seconds
+addr: isCA
+addr: copy_dn
+addr: signer_key_type
+addr: signer_hash_id
+
+cc: read8-low ( -- x ) {
+ if (CTX->hlen == 0) {
+ T0_PUSHi(-1);
+ } else {
+ unsigned char x = *CTX->hbuf ++;
+ if (CTX->copy_dn && CTX->append_dn) {
+ CTX->append_dn(CTX->append_dn_ctx, &x, 1);
+ }
+ CTX->hlen --;
+ T0_PUSH(x);
+ }
+}
+
+cc: read-blob-inner ( addr len -- addr len ) {
+ uint32_t len = T0_POP();
+ uint32_t addr = T0_POP();
+ size_t clen = CTX->hlen;
+ if (clen > len) {
+ clen = (size_t)len;
+ }
+ if (addr != 0) {
+ memcpy((unsigned char *)CTX + addr, CTX->hbuf, clen);
+ }
+ if (CTX->copy_dn && CTX->append_dn) {
+ CTX->append_dn(CTX->append_dn_ctx, CTX->hbuf, clen);
+ }
+ CTX->hbuf += clen;
+ CTX->hlen -= clen;
+ T0_PUSH(addr + clen);
+ T0_PUSH(len - clen);
+}
+
+\ Get the address and length for the pkey_data buffer.
+: addr-len-pkey_data ( -- addr len )
+ CX 0 8191 { offsetof(br_x509_decoder_context, pkey_data) }
+ CX 0 8191 { BR_X509_BUFSIZE_KEY } ;
+
+\ Copy the public key (RSA) to the permanent buffer.
+cc: copy-rsa-pkey ( nlen elen -- ) {
+ size_t elen = T0_POP();
+ size_t nlen = T0_POP();
+ CTX->pkey.key_type = BR_KEYTYPE_RSA;
+ CTX->pkey.key.rsa.n = CTX->pkey_data;
+ CTX->pkey.key.rsa.nlen = nlen;
+ CTX->pkey.key.rsa.e = CTX->pkey_data + nlen;
+ CTX->pkey.key.rsa.elen = elen;
+}
+
+\ Copy the public key (EC) to the permanent buffer.
+cc: copy-ec-pkey ( curve qlen -- ) {
+ size_t qlen = T0_POP();
+ uint32_t curve = T0_POP();
+ CTX->pkey.key_type = BR_KEYTYPE_EC;
+ CTX->pkey.key.ec.curve = curve;
+ CTX->pkey.key.ec.q = CTX->pkey_data;
+ CTX->pkey.key.ec.qlen = qlen;
+}
+
+\ Extensions with specific processing.
+OID: basicConstraints 2.5.29.19
+
+\ Process a Basic Constraints extension. We want the "CA" flag only.
+: process-basicConstraints ( lim -- lim )
+ read-sequence-open
+ read-tag-or-end dup 0x01 = if
+ read-boolean 1 and addr-isCA set8
+ else
+ 2drop
+ then
+ skip-close-elt
+ ;
+
+\ Decode a certificate.
+: main ( -- ! )
+
+ \ Initialise state flags.
+ 0 addr-decoded set8
+ 0 addr-copy_dn set8
+
+ \ An arbitrary limit for the total certificate size.
+ 0xFFFFFF
+
+ \ Open the outer SEQUENCE.
+ read-sequence-open
+
+ \ TBS
+ read-sequence-open
+
+ \ First element may be an explicit version. We accept only
+ \ versions 0 to 2 (certificates v1 to v3).
+ read-tag dup 0x20 = if
+ drop check-constructed read-length-open-elt
+ read-tag
+ 0x02 check-tag-primitive
+ read-small-int-value
+ 2 > if ERR_X509_UNSUPPORTED fail then
+ close-elt
+ read-tag
+ then
+
+ \ Serial number. We just check that the tag is correct.
+ 0x02 check-tag-primitive read-length-skip
+
+ \ Signature algorithm.
+ read-sequence-open skip-close-elt
+
+ \ Issuer name.
+ read-sequence-open skip-close-elt
+
+ \ Validity dates.
+ read-sequence-open
+ read-date addr-notbefore_seconds set32 addr-notbefore_days set32
+ read-date addr-notafter_seconds set32 addr-notafter_days set32
+ close-elt
+
+ \ Subject name.
+ 1 addr-copy_dn set8
+ read-sequence-open skip-close-elt
+ 0 addr-copy_dn set8
+
+ \ Public Key.
+ read-sequence-open
+ \ Algorithm Identifier. Right now we are only interested in the
+ \ OID, since we only support RSA keys.
+ \ TODO: support EC keys
+ read-sequence-open
+ read-OID ifnot ERR_X509_UNSUPPORTED fail then
+ choice
+ \ RSA public key.
+ rsaEncryption eqOID uf
+ skip-close-elt
+ \ Public key itself: the BIT STRING contains bytes
+ \ (no partial byte) and these bytes encode the
+ \ actual value.
+ read-bits-open
+ \ RSA public key is a SEQUENCE of two
+ \ INTEGER. We get both INTEGER values into
+ \ the pkey_data[] buffer, if they fit.
+ read-sequence-open
+ addr-len-pkey_data
+ read-integer { nlen }
+ addr-len-pkey_data swap nlen + swap nlen -
+ read-integer { elen }
+ close-elt
+ close-elt
+ nlen elen copy-rsa-pkey
+ enduf
+
+ \ EC public key.
+ id-ecPublicKey eqOID uf
+ \ We support only named curves, for which the
+ \ "parameters" field in the AlgorithmIdentifier
+ \ field should be an OID.
+ read-curve-ID { curve }
+ close-elt
+ read-bits-open
+ dup { qlen }
+ dup addr-len-pkey_data rot < if
+ ERR_X509_LIMIT_EXCEEDED fail
+ then
+ read-blob
+ curve qlen copy-ec-pkey
+ enduf
+ ERR_X509_UNSUPPORTED fail
+ endchoice
+ close-elt
+
+ \ This flag will be set to true if the Basic Constraints extension
+ \ is encountered.
+ 0 addr-isCA set8
+
+ \ Skip issuerUniqueID and subjectUniqueID, and process extensions
+ \ if present. Extensions are an explicit context tag of value 3
+ \ around a SEQUENCE OF extensions. Each extension is a SEQUENCE
+ \ with an OID, an optional boolean, and a value; the value is
+ \ an OCTET STRING.
+ read-tag-or-end
+ 0x21 iftag-skip
+ 0x22 iftag-skip
+ dup 0x23 = if
+ drop
+ check-constructed read-length-open-elt
+ read-sequence-open
+ begin dup while
+ read-sequence-open
+ read-OID drop
+ read-tag dup 0x01 = if
+ read-boolean drop
+ read-tag
+ then
+ 0x04 check-tag-primitive read-length-open-elt
+ choice
+ \ Extensions with specific processing.
+ basicConstraints eqOID uf
+ process-basicConstraints
+ enduf
+ skip-remaining
+ endchoice
+ close-elt
+ close-elt
+ repeat
+ close-elt
+ close-elt
+ else
+ -1 = ifnot ERR_X509_UNEXPECTED fail then
+ drop
+ then
+
+ close-elt
+
+ \ signature algorithm
+ read-sequence-open
+ read-OID if
+ choice
+ sha1WithRSAEncryption eqOID uf 2 KEYTYPE_RSA enduf
+ sha224WithRSAEncryption eqOID uf 3 KEYTYPE_RSA enduf
+ sha256WithRSAEncryption eqOID uf 4 KEYTYPE_RSA enduf
+ sha384WithRSAEncryption eqOID uf 5 KEYTYPE_RSA enduf
+ sha512WithRSAEncryption eqOID uf 6 KEYTYPE_RSA enduf
+
+ ecdsa-with-SHA1 eqOID uf 2 KEYTYPE_EC enduf
+ ecdsa-with-SHA224 eqOID uf 3 KEYTYPE_EC enduf
+ ecdsa-with-SHA256 eqOID uf 4 KEYTYPE_EC enduf
+ ecdsa-with-SHA384 eqOID uf 5 KEYTYPE_EC enduf
+ ecdsa-with-SHA512 eqOID uf 6 KEYTYPE_EC enduf
+
+ 0 0
+ endchoice
+ else
+ 0 0
+ then
+ addr-signer_key_type set8
+ addr-signer_hash_id set8
+ skip-close-elt
+ \ read-sequence-open skip-close-elt
+
+ \ signature value
+ read-bits-open skip-close-elt
+
+ \ Close the outer SEQUENCE.
+ close-elt
+ drop
+
+ \ Mark the decoding as successful.
+ 1 addr-decoded set8
+
+ \ Read one byte, then fail: if the read succeeds, then there is
+ \ some trailing byte.
+ read8-nc ERR_X509_EXTRA_ELEMENT fail
+ ;
diff --git a/test/monniaux/BearSSL/src/x509/x509_knownkey.c b/test/monniaux/BearSSL/src/x509/x509_knownkey.c
new file mode 100644
index 00000000..7674f3fd
--- /dev/null
+++ b/test/monniaux/BearSSL/src/x509/x509_knownkey.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_x509.h */
+void
+br_x509_knownkey_init_rsa(br_x509_knownkey_context *ctx,
+ const br_rsa_public_key *pk, unsigned usages)
+{
+ ctx->vtable = &br_x509_knownkey_vtable;
+ ctx->pkey.key_type = BR_KEYTYPE_RSA;
+ ctx->pkey.key.rsa = *pk;
+ ctx->usages = usages;
+}
+
+/* see bearssl_x509.h */
+void
+br_x509_knownkey_init_ec(br_x509_knownkey_context *ctx,
+ const br_ec_public_key *pk, unsigned usages)
+{
+ ctx->vtable = &br_x509_knownkey_vtable;
+ ctx->pkey.key_type = BR_KEYTYPE_EC;
+ ctx->pkey.key.ec = *pk;
+ ctx->usages = usages;
+}
+
+static void
+kk_start_chain(const br_x509_class **ctx, const char *server_name)
+{
+ (void)ctx;
+ (void)server_name;
+}
+
+static void
+kk_start_cert(const br_x509_class **ctx, uint32_t length)
+{
+ (void)ctx;
+ (void)length;
+}
+
+static void
+kk_append(const br_x509_class **ctx, const unsigned char *buf, size_t len)
+{
+ (void)ctx;
+ (void)buf;
+ (void)len;
+}
+
+static void
+kk_end_cert(const br_x509_class **ctx)
+{
+ (void)ctx;
+}
+
+static unsigned
+kk_end_chain(const br_x509_class **ctx)
+{
+ (void)ctx;
+ return 0;
+}
+
+static const br_x509_pkey *
+kk_get_pkey(const br_x509_class *const *ctx, unsigned *usages)
+{
+ const br_x509_knownkey_context *xc;
+
+ xc = (const br_x509_knownkey_context *)ctx;
+ if (usages != NULL) {
+ *usages = xc->usages;
+ }
+ return &xc->pkey;
+}
+
+/* see bearssl_x509.h */
+const br_x509_class br_x509_knownkey_vtable = {
+ sizeof(br_x509_knownkey_context),
+ kk_start_chain,
+ kk_start_cert,
+ kk_append,
+ kk_end_cert,
+ kk_end_chain,
+ kk_get_pkey
+};
diff --git a/test/monniaux/BearSSL/src/x509/x509_minimal.c b/test/monniaux/BearSSL/src/x509/x509_minimal.c
new file mode 100644
index 00000000..3b876ef8
--- /dev/null
+++ b/test/monniaux/BearSSL/src/x509/x509_minimal.c
@@ -0,0 +1,1713 @@
+/* Automatically generated code; do not modify directly. */
+
+#include <stddef.h>
+#include <stdint.h>
+
+typedef struct {
+ uint32_t *dp;
+ uint32_t *rp;
+ const unsigned char *ip;
+} t0_context;
+
+static uint32_t
+t0_parse7E_unsigned(const unsigned char **p)
+{
+ uint32_t x;
+
+ x = 0;
+ for (;;) {
+ unsigned y;
+
+ y = *(*p) ++;
+ x = (x << 7) | (uint32_t)(y & 0x7F);
+ if (y < 0x80) {
+ return x;
+ }
+ }
+}
+
+static int32_t
+t0_parse7E_signed(const unsigned char **p)
+{
+ int neg;
+ uint32_t x;
+
+ neg = ((**p) >> 6) & 1;
+ x = (uint32_t)-neg;
+ for (;;) {
+ unsigned y;
+
+ y = *(*p) ++;
+ x = (x << 7) | (uint32_t)(y & 0x7F);
+ if (y < 0x80) {
+ if (neg) {
+ return -(int32_t)~x - 1;
+ } else {
+ return (int32_t)x;
+ }
+ }
+ }
+}
+
+#define T0_VBYTE(x, n) (unsigned char)((((uint32_t)(x) >> (n)) & 0x7F) | 0x80)
+#define T0_FBYTE(x, n) (unsigned char)(((uint32_t)(x) >> (n)) & 0x7F)
+#define T0_SBYTE(x) (unsigned char)((((uint32_t)(x) >> 28) + 0xF8) ^ 0xF8)
+#define T0_INT1(x) T0_FBYTE(x, 0)
+#define T0_INT2(x) T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+#define T0_INT3(x) T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+#define T0_INT4(x) T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+#define T0_INT5(x) T0_SBYTE(x), T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+
+/* static const unsigned char t0_datablock[]; */
+
+
+void br_x509_minimal_init_main(void *t0ctx);
+
+void br_x509_minimal_run(void *t0ctx);
+
+
+
+#include "inner.h"
+
+
+
+
+
+#include "inner.h"
+
+/*
+ * Implementation Notes
+ * --------------------
+ *
+ * The C code pushes the data by chunks; all decoding is done in the
+ * T0 code. The cert_length value is set to the certificate length when
+ * a new certificate is started; the T0 code picks it up as outer limit,
+ * and decoding functions use it to ensure that no attempt is made at
+ * reading past it. The T0 code also checks that once the certificate is
+ * decoded, there are no trailing bytes.
+ *
+ * The T0 code sets cert_length to 0 when the certificate is fully
+ * decoded.
+ *
+ * The C code must still perform two checks:
+ *
+ * -- If the certificate length is 0, then the T0 code will not be
+ * invoked at all. This invalid condition must thus be reported by the
+ * C code.
+ *
+ * -- When reaching the end of certificate, the C code must verify that
+ * the certificate length has been set to 0, thereby signaling that
+ * the T0 code properly decoded a certificate.
+ *
+ * Processing of a chain works in the following way:
+ *
+ * -- The error flag is set to a non-zero value when validation is
+ * finished. The value is either BR_ERR_X509_OK (validation is
+ * successful) or another non-zero error code. When a non-zero error
+ * code is obtained, the remaining bytes in the current certificate and
+ * the subsequent certificates (if any) are completely ignored.
+ *
+ * -- Each certificate is decoded in due course, with the following
+ * "interesting points":
+ *
+ * -- Start of the TBS: the multihash engine is reset and activated.
+ *
+ * -- Start of the issuer DN: the secondary hash engine is started,
+ * to process the encoded issuer DN.
+ *
+ * -- End of the issuer DN: the secondary hash engine is stopped. The
+ * resulting hash value is computed and then copied into the
+ * next_dn_hash[] buffer.
+ *
+ * -- Start of the subject DN: the secondary hash engine is started,
+ * to process the encoded subject DN.
+ *
+ * -- For the EE certificate only: the Common Name, if any, is matched
+ * against the expected server name.
+ *
+ * -- End of the subject DN: the secondary hash engine is stopped. The
+ * resulting hash value is computed into the pad. It is then processed:
+ *
+ * -- If this is the EE certificate, then the hash is ignored
+ * (except for direct trust processing, see later; the hash is
+ * simply left in current_dn_hash[]).
+ *
+ * -- Otherwise, the hashed subject DN is compared with the saved
+ * hash value (in saved_dn_hash[]). They must match.
+ *
+ * Either way, the next_dn_hash[] value is then copied into the
+ * saved_dn_hash[] value. Thus, at that point, saved_dn_hash[]
+ * contains the hash of the issuer DN for the current certificate,
+ * and current_dn_hash[] contains the hash of the subject DN for the
+ * current certificate.
+ *
+ * -- Public key: it is decoded into the cert_pkey[] buffer. Unknown
+ * key types are reported at that point.
+ *
+ * -- If this is the EE certificate, then the key type is compared
+ * with the expected key type (initialization parameter). The public
+ * key data is copied to ee_pkey_data[]. The key and hashed subject
+ * DN are also compared with the "direct trust" keys; if the key
+ * and DN are matched, then validation ends with a success.
+ *
+ * -- Otherwise, the saved signature (cert_sig[]) is verified
+ * against the saved TBS hash (tbs_hash[]) and that freshly
+ * decoded public key. Failure here ends validation with an error.
+ *
+ * -- Extensions: extension values are processed in due order.
+ *
+ * -- Basic Constraints: for all certificates except EE, must be
+ * present, indicate a CA, and have a path legnth compatible with
+ * the chain length so far.
+ *
+ * -- Key Usage: for the EE, if present, must allow signatures
+ * or encryption/key exchange, as required for the cipher suite.
+ * For non-EE, if present, must have the "certificate sign" bit.
+ *
+ * -- Subject Alt Name: for the EE, dNSName names are matched
+ * against the server name. Ignored for non-EE.
+ *
+ * -- Authority Key Identifier, Subject Key Identifier, Issuer
+ * Alt Name, Subject Directory Attributes, CRL Distribution Points
+ * Freshest CRL, Authority Info Access and Subject Info Access
+ * extensions are always ignored: they either contain only
+ * informative data, or they relate to revocation processing, which
+ * we explicitly do not support.
+ *
+ * -- All other extensions are ignored if non-critical. If a
+ * critical extension other than the ones above is encountered,
+ * then a failure is reported.
+ *
+ * -- End of the TBS: the multihash engine is stopped.
+ *
+ * -- Signature algorithm: the signature algorithm on the
+ * certificate is decoded. A failure is reported if that algorithm
+ * is unknown. The hashed TBS corresponding to the signature hash
+ * function is computed and stored in tbs_hash[] (if not supported,
+ * then a failure is reported). The hash OID and length are stored
+ * in cert_sig_hash_oid and cert_sig_hash_len.
+ *
+ * -- Signature value: the signature value is copied into the
+ * cert_sig[] array.
+ *
+ * -- Certificate end: the hashed issuer DN (saved_dn_hash[]) is
+ * looked up in the trust store (CA trust anchors only); for all
+ * that match, the signature (cert_sig[]) is verified against the
+ * anchor public key (hashed TBS is in tbs_hash[]). If one of these
+ * signatures is valid, then validation ends with a success.
+ *
+ * -- If the chain end is reached without obtaining a validation success,
+ * then validation is reported as failed.
+ */
+
+#if BR_USE_UNIX_TIME
+#include <time.h>
+#endif
+
+#if BR_USE_WIN32_TIME
+#include <windows.h>
+#endif
+
+/*
+ * The T0 compiler will produce these prototypes declarations in the
+ * header.
+ *
+void br_x509_minimal_init_main(void *ctx);
+void br_x509_minimal_run(void *ctx);
+ */
+
+/* see bearssl_x509.h */
+void
+br_x509_minimal_init(br_x509_minimal_context *ctx,
+ const br_hash_class *dn_hash_impl,
+ const br_x509_trust_anchor *trust_anchors, size_t trust_anchors_num)
+{
+ memset(ctx, 0, sizeof *ctx);
+ ctx->vtable = &br_x509_minimal_vtable;
+ ctx->dn_hash_impl = dn_hash_impl;
+ ctx->trust_anchors = trust_anchors;
+ ctx->trust_anchors_num = trust_anchors_num;
+}
+
+static void
+xm_start_chain(const br_x509_class **ctx, const char *server_name)
+{
+ br_x509_minimal_context *cc;
+ size_t u;
+
+ cc = (br_x509_minimal_context *)(void *)ctx;
+ for (u = 0; u < cc->num_name_elts; u ++) {
+ cc->name_elts[u].status = 0;
+ cc->name_elts[u].buf[0] = 0;
+ }
+ memset(&cc->pkey, 0, sizeof cc->pkey);
+ cc->num_certs = 0;
+ cc->err = 0;
+ cc->cpu.dp = cc->dp_stack;
+ cc->cpu.rp = cc->rp_stack;
+ br_x509_minimal_init_main(&cc->cpu);
+ if (server_name == NULL || *server_name == 0) {
+ cc->server_name = NULL;
+ } else {
+ cc->server_name = server_name;
+ }
+}
+
+static void
+xm_start_cert(const br_x509_class **ctx, uint32_t length)
+{
+ br_x509_minimal_context *cc;
+
+ cc = (br_x509_minimal_context *)(void *)ctx;
+ if (cc->err != 0) {
+ return;
+ }
+ if (length == 0) {
+ cc->err = BR_ERR_X509_TRUNCATED;
+ return;
+ }
+ cc->cert_length = length;
+}
+
+static void
+xm_append(const br_x509_class **ctx, const unsigned char *buf, size_t len)
+{
+ br_x509_minimal_context *cc;
+
+ cc = (br_x509_minimal_context *)(void *)ctx;
+ if (cc->err != 0) {
+ return;
+ }
+ cc->hbuf = buf;
+ cc->hlen = len;
+ br_x509_minimal_run(&cc->cpu);
+}
+
+static void
+xm_end_cert(const br_x509_class **ctx)
+{
+ br_x509_minimal_context *cc;
+
+ cc = (br_x509_minimal_context *)(void *)ctx;
+ if (cc->err == 0 && cc->cert_length != 0) {
+ cc->err = BR_ERR_X509_TRUNCATED;
+ }
+ cc->num_certs ++;
+}
+
+static unsigned
+xm_end_chain(const br_x509_class **ctx)
+{
+ br_x509_minimal_context *cc;
+
+ cc = (br_x509_minimal_context *)(void *)ctx;
+ if (cc->err == 0) {
+ if (cc->num_certs == 0) {
+ cc->err = BR_ERR_X509_EMPTY_CHAIN;
+ } else {
+ cc->err = BR_ERR_X509_NOT_TRUSTED;
+ }
+ } else if (cc->err == BR_ERR_X509_OK) {
+ return 0;
+ }
+ return (unsigned)cc->err;
+}
+
+static const br_x509_pkey *
+xm_get_pkey(const br_x509_class *const *ctx, unsigned *usages)
+{
+ br_x509_minimal_context *cc;
+
+ cc = (br_x509_minimal_context *)(void *)ctx;
+ if (cc->err == BR_ERR_X509_OK
+ || cc->err == BR_ERR_X509_NOT_TRUSTED)
+ {
+ if (usages != NULL) {
+ *usages = cc->key_usages;
+ }
+ return &((br_x509_minimal_context *)(void *)ctx)->pkey;
+ } else {
+ return NULL;
+ }
+}
+
+/* see bearssl_x509.h */
+const br_x509_class br_x509_minimal_vtable = {
+ sizeof(br_x509_minimal_context),
+ xm_start_chain,
+ xm_start_cert,
+ xm_append,
+ xm_end_cert,
+ xm_end_chain,
+ xm_get_pkey
+};
+
+#define CTX ((br_x509_minimal_context *)(void *)((unsigned char *)t0ctx - offsetof(br_x509_minimal_context, cpu)))
+#define CONTEXT_NAME br_x509_minimal_context
+
+#define DNHASH_LEN ((CTX->dn_hash_impl->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK)
+
+/*
+ * Hash a DN (from a trust anchor) into the provided buffer. This uses the
+ * DN hash implementation and context structure from the X.509 engine
+ * context.
+ */
+static void
+hash_dn(br_x509_minimal_context *ctx, const void *dn, size_t len,
+ unsigned char *out)
+{
+ ctx->dn_hash_impl->init(&ctx->dn_hash.vtable);
+ ctx->dn_hash_impl->update(&ctx->dn_hash.vtable, dn, len);
+ ctx->dn_hash_impl->out(&ctx->dn_hash.vtable, out);
+}
+
+/*
+ * Compare two big integers for equality. The integers use unsigned big-endian
+ * encoding; extra leading bytes (of value 0) are allowed.
+ */
+static int
+eqbigint(const unsigned char *b1, size_t len1,
+ const unsigned char *b2, size_t len2)
+{
+ while (len1 > 0 && *b1 == 0) {
+ b1 ++;
+ len1 --;
+ }
+ while (len2 > 0 && *b2 == 0) {
+ b2 ++;
+ len2 --;
+ }
+ if (len1 != len2) {
+ return 0;
+ }
+ return memcmp(b1, b2, len1) == 0;
+}
+
+/*
+ * Compare two strings for equality, in a case-insensitive way. This
+ * function handles casing only for ASCII letters.
+ */
+static int
+eqnocase(const void *s1, const void *s2, size_t len)
+{
+ const unsigned char *buf1, *buf2;
+
+ buf1 = s1;
+ buf2 = s2;
+ while (len -- > 0) {
+ int x1, x2;
+
+ x1 = *buf1 ++;
+ x2 = *buf2 ++;
+ if (x1 >= 'A' && x1 <= 'Z') {
+ x1 += 'a' - 'A';
+ }
+ if (x2 >= 'A' && x2 <= 'Z') {
+ x2 += 'a' - 'A';
+ }
+ if (x1 != x2) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static int verify_signature(br_x509_minimal_context *ctx,
+ const br_x509_pkey *pk);
+
+
+
+static const unsigned char t0_datablock[] = {
+ 0x00, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x09,
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x05, 0x09, 0x2A, 0x86,
+ 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0E, 0x09, 0x2A, 0x86, 0x48, 0x86,
+ 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D,
+ 0x01, 0x01, 0x0C, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01,
+ 0x0D, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x09, 0x60, 0x86, 0x48, 0x01,
+ 0x65, 0x03, 0x04, 0x02, 0x04, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
+ 0x04, 0x02, 0x01, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02,
+ 0x02, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x07,
+ 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x08, 0x2A, 0x86, 0x48, 0xCE,
+ 0x3D, 0x03, 0x01, 0x07, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x22, 0x05, 0x2B,
+ 0x81, 0x04, 0x00, 0x23, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x01,
+ 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x01, 0x08, 0x2A, 0x86,
+ 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D,
+ 0x04, 0x03, 0x03, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x04,
+ 0x03, 0x55, 0x04, 0x03, 0x00, 0x1F, 0x03, 0xFC, 0x07, 0x7F, 0x0B, 0x5E,
+ 0x0F, 0x1F, 0x12, 0xFE, 0x16, 0xBF, 0x1A, 0x9F, 0x1E, 0x7E, 0x22, 0x3F,
+ 0x26, 0x1E, 0x29, 0xDF, 0x00, 0x1F, 0x03, 0xFD, 0x07, 0x9F, 0x0B, 0x7E,
+ 0x0F, 0x3F, 0x13, 0x1E, 0x16, 0xDF, 0x1A, 0xBF, 0x1E, 0x9E, 0x22, 0x5F,
+ 0x26, 0x3E, 0x29, 0xFF, 0x03, 0x55, 0x1D, 0x13, 0x03, 0x55, 0x1D, 0x0F,
+ 0x03, 0x55, 0x1D, 0x11, 0x03, 0x55, 0x1D, 0x20, 0x08, 0x2B, 0x06, 0x01,
+ 0x05, 0x05, 0x07, 0x02, 0x01, 0x03, 0x55, 0x1D, 0x23, 0x03, 0x55, 0x1D,
+ 0x0E, 0x03, 0x55, 0x1D, 0x12, 0x03, 0x55, 0x1D, 0x09, 0x03, 0x55, 0x1D,
+ 0x1F, 0x03, 0x55, 0x1D, 0x2E, 0x08, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07,
+ 0x01, 0x01, 0x08, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x0B
+};
+
+static const unsigned char t0_codeblock[] = {
+ 0x00, 0x01, 0x00, 0x0D, 0x00, 0x00, 0x01, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x11, 0x00, 0x00, 0x01, 0x01, 0x09, 0x00, 0x00, 0x01, 0x01, 0x0A,
+ 0x00, 0x00, 0x24, 0x24, 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_BAD_BOOLEAN), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_BAD_DN), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_BAD_SERVER_NAME), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_BAD_TAG_CLASS), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_BAD_TAG_VALUE), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_BAD_TIME), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_CRITICAL_EXTENSION), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_DN_MISMATCH), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_EXPIRED), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_EXTRA_ELEMENT), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_FORBIDDEN_KEY_USAGE), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_INDEFINITE_LENGTH), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_INNER_TRUNC), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_LIMIT_EXCEEDED), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_NOT_CA), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_NOT_CONSTRUCTED), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_NOT_PRIMITIVE), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_OVERFLOW), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_PARTIAL_BYTE), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_UNEXPECTED), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_UNSUPPORTED), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_WEAK_PUBLIC_KEY), 0x00, 0x00, 0x01,
+ T0_INT1(BR_KEYTYPE_EC), 0x00, 0x00, 0x01, T0_INT1(BR_KEYTYPE_RSA),
+ 0x00, 0x00, 0x01, T0_INT2(offsetof(CONTEXT_NAME, cert_length)), 0x00,
+ 0x00, 0x01, T0_INT2(offsetof(CONTEXT_NAME, cert_sig)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(CONTEXT_NAME, cert_sig_hash_len)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(CONTEXT_NAME, cert_sig_hash_oid)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(CONTEXT_NAME, cert_sig_len)), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(CONTEXT_NAME, cert_signer_key_type)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(CONTEXT_NAME, current_dn_hash)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(CONTEXT_NAME, key_usages)), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_x509_minimal_context, pkey_data)), 0x01,
+ T0_INT2(BR_X509_BUFSIZE_KEY), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(CONTEXT_NAME, min_rsa_size)), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(CONTEXT_NAME, next_dn_hash)), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(CONTEXT_NAME, num_certs)), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(CONTEXT_NAME, pad)), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(CONTEXT_NAME, saved_dn_hash)), 0x00, 0x00, 0xC9, 0x71,
+ 0x00, 0x00, 0x01, 0x80, 0x73, 0x00, 0x00, 0x01, 0x80, 0x7C, 0x00, 0x00,
+ 0x01, 0x81, 0x02, 0x00, 0x00, 0x92, 0x05, 0x05, 0x34, 0x42, 0x01, 0x00,
+ 0x00, 0x34, 0x01, 0x0A, 0x0E, 0x09, 0x01, 0x9A, 0xFF, 0xB8, 0x00, 0x0A,
+ 0x00, 0x00, 0x01, 0x82, 0x19, 0x00, 0x00, 0x01, 0x82, 0x01, 0x00, 0x00,
+ 0x01, 0x81, 0x68, 0x00, 0x04, 0x03, 0x00, 0x03, 0x01, 0x03, 0x02, 0x03,
+ 0x03, 0x02, 0x03, 0x02, 0x01, 0x11, 0x06, 0x07, 0x02, 0x02, 0x02, 0x00,
+ 0x0D, 0x04, 0x05, 0x02, 0x03, 0x02, 0x01, 0x0D, 0x00, 0x02, 0x03, 0x00,
+ 0x03, 0x01, 0x25, 0x02, 0x01, 0x13, 0x3B, 0x02, 0x00, 0x0F, 0x15, 0x00,
+ 0x00, 0x01, 0x81, 0x74, 0x00, 0x00, 0x05, 0x02, 0x52, 0x28, 0x00, 0x00,
+ 0x06, 0x02, 0x53, 0x28, 0x00, 0x00, 0x01, 0x10, 0x77, 0x00, 0x00, 0x11,
+ 0x05, 0x02, 0x56, 0x28, 0x74, 0x00, 0x00, 0x11, 0x05, 0x02, 0x56, 0x28,
+ 0x75, 0x00, 0x00, 0x06, 0x02, 0x4C, 0x28, 0x00, 0x00, 0x01, 0x82, 0x11,
+ 0x00, 0x00, 0x25, 0x20, 0x01, 0x08, 0x0E, 0x3B, 0x40, 0x20, 0x09, 0x00,
+ 0x09, 0x03, 0x00, 0x5B, 0x2B, 0xAF, 0x39, 0xAF, 0xB3, 0x25, 0x01, 0x20,
+ 0x11, 0x06, 0x11, 0x24, 0x74, 0xAD, 0xB3, 0x01, 0x02, 0x78, 0xB0, 0x01,
+ 0x02, 0x12, 0x06, 0x02, 0x57, 0x28, 0x79, 0xB3, 0x01, 0x02, 0x78, 0xAE,
+ 0xAF, 0xC2, 0x9C, 0x65, 0x61, 0x21, 0x16, 0xAF, 0xA7, 0x29, 0x69, 0x06,
+ 0x02, 0x4B, 0x28, 0xA7, 0x29, 0x71, 0x06, 0x02, 0x4B, 0x28, 0x79, 0x02,
+ 0x00, 0x06, 0x05, 0x9D, 0x03, 0x01, 0x04, 0x09, 0x9C, 0x61, 0x68, 0x21,
+ 0x27, 0x05, 0x02, 0x4A, 0x28, 0x68, 0x65, 0x21, 0x16, 0xAF, 0xAF, 0x9E,
+ 0x05, 0x02, 0x57, 0x28, 0xBC, 0x26, 0x06, 0x27, 0xC2, 0xA4, 0xAF, 0x63,
+ 0xAA, 0x03, 0x03, 0x63, 0x3B, 0x02, 0x03, 0x09, 0x3B, 0x02, 0x03, 0x0A,
+ 0xAA, 0x03, 0x04, 0x79, 0x64, 0x2A, 0x01, 0x81, 0x00, 0x09, 0x02, 0x03,
+ 0x12, 0x06, 0x02, 0x58, 0x28, 0x79, 0x5A, 0x03, 0x02, 0x04, 0x3A, 0x88,
+ 0x26, 0x06, 0x34, 0x9E, 0x05, 0x02, 0x57, 0x28, 0x6A, 0x26, 0x06, 0x04,
+ 0x01, 0x17, 0x04, 0x12, 0x6B, 0x26, 0x06, 0x04, 0x01, 0x18, 0x04, 0x0A,
+ 0x6C, 0x26, 0x06, 0x04, 0x01, 0x19, 0x04, 0x02, 0x57, 0x28, 0x03, 0x05,
+ 0x79, 0xA4, 0x25, 0x03, 0x06, 0x25, 0x63, 0x34, 0x0D, 0x06, 0x02, 0x50,
+ 0x28, 0xA5, 0x59, 0x03, 0x02, 0x04, 0x02, 0x57, 0x28, 0x79, 0x02, 0x00,
+ 0x06, 0x21, 0x02, 0x02, 0x5A, 0x30, 0x11, 0x06, 0x08, 0x24, 0x02, 0x03,
+ 0x02, 0x04, 0x1D, 0x04, 0x10, 0x59, 0x30, 0x11, 0x06, 0x08, 0x24, 0x02,
+ 0x05, 0x02, 0x06, 0x1C, 0x04, 0x03, 0x57, 0x28, 0x24, 0x04, 0x24, 0x02,
+ 0x02, 0x5A, 0x30, 0x11, 0x06, 0x08, 0x24, 0x02, 0x03, 0x02, 0x04, 0x23,
+ 0x04, 0x10, 0x59, 0x30, 0x11, 0x06, 0x08, 0x24, 0x02, 0x05, 0x02, 0x06,
+ 0x22, 0x04, 0x03, 0x57, 0x28, 0x24, 0x25, 0x06, 0x01, 0x28, 0x24, 0x01,
+ 0x00, 0x03, 0x07, 0xB4, 0x01, 0x21, 0x8F, 0x01, 0x22, 0x8F, 0x25, 0x01,
+ 0x23, 0x11, 0x06, 0x81, 0x26, 0x24, 0x74, 0xAD, 0xAF, 0x25, 0x06, 0x81,
+ 0x1A, 0x01, 0x00, 0x03, 0x08, 0xAF, 0x9E, 0x24, 0xB3, 0x25, 0x01, 0x01,
+ 0x11, 0x06, 0x04, 0xA6, 0x03, 0x08, 0xB3, 0x01, 0x04, 0x78, 0xAD, 0x70,
+ 0x26, 0x06, 0x0F, 0x02, 0x00, 0x06, 0x03, 0xC3, 0x04, 0x05, 0x99, 0x01,
+ 0x7F, 0x03, 0x07, 0x04, 0x80, 0x6C, 0x91, 0x26, 0x06, 0x06, 0x02, 0x00,
+ 0x9B, 0x04, 0x80, 0x62, 0xC5, 0x26, 0x06, 0x11, 0x02, 0x00, 0x06, 0x09,
+ 0x01, 0x00, 0x03, 0x01, 0x98, 0x03, 0x01, 0x04, 0x01, 0xC3, 0x04, 0x80,
+ 0x4D, 0x73, 0x26, 0x06, 0x0A, 0x02, 0x08, 0x06, 0x03, 0x9A, 0x04, 0x01,
+ 0xC3, 0x04, 0x3F, 0x6F, 0x26, 0x06, 0x03, 0xC3, 0x04, 0x38, 0xC8, 0x26,
+ 0x06, 0x03, 0xC3, 0x04, 0x31, 0x90, 0x26, 0x06, 0x03, 0xC3, 0x04, 0x2A,
+ 0xC6, 0x26, 0x06, 0x03, 0xC3, 0x04, 0x23, 0x7A, 0x26, 0x06, 0x03, 0xC3,
+ 0x04, 0x1C, 0x85, 0x26, 0x06, 0x03, 0xC3, 0x04, 0x15, 0x6E, 0x26, 0x06,
+ 0x03, 0xC3, 0x04, 0x0E, 0xC7, 0x26, 0x06, 0x03, 0xC3, 0x04, 0x07, 0x02,
+ 0x08, 0x06, 0x02, 0x49, 0x28, 0xC3, 0x79, 0x79, 0x04, 0xFE, 0x62, 0x79,
+ 0x79, 0x04, 0x08, 0x01, 0x7F, 0x11, 0x05, 0x02, 0x56, 0x28, 0x24, 0x79,
+ 0x3A, 0x02, 0x00, 0x06, 0x08, 0x02, 0x01, 0x3C, 0x2F, 0x05, 0x02, 0x45,
+ 0x28, 0x02, 0x00, 0x06, 0x01, 0x17, 0x02, 0x00, 0x02, 0x07, 0x2F, 0x05,
+ 0x02, 0x51, 0x28, 0xB3, 0x76, 0xAD, 0x9E, 0x06, 0x80, 0x77, 0xBD, 0x26,
+ 0x06, 0x07, 0x01, 0x02, 0x5A, 0x8A, 0x04, 0x80, 0x5E, 0xBE, 0x26, 0x06,
+ 0x07, 0x01, 0x03, 0x5A, 0x8B, 0x04, 0x80, 0x53, 0xBF, 0x26, 0x06, 0x07,
+ 0x01, 0x04, 0x5A, 0x8C, 0x04, 0x80, 0x48, 0xC0, 0x26, 0x06, 0x06, 0x01,
+ 0x05, 0x5A, 0x8D, 0x04, 0x3E, 0xC1, 0x26, 0x06, 0x06, 0x01, 0x06, 0x5A,
+ 0x8E, 0x04, 0x34, 0x7F, 0x26, 0x06, 0x06, 0x01, 0x02, 0x59, 0x8A, 0x04,
+ 0x2A, 0x80, 0x26, 0x06, 0x06, 0x01, 0x03, 0x59, 0x8B, 0x04, 0x20, 0x81,
+ 0x26, 0x06, 0x06, 0x01, 0x04, 0x59, 0x8C, 0x04, 0x16, 0x82, 0x26, 0x06,
+ 0x06, 0x01, 0x05, 0x59, 0x8D, 0x04, 0x0C, 0x83, 0x26, 0x06, 0x06, 0x01,
+ 0x06, 0x59, 0x8E, 0x04, 0x02, 0x57, 0x28, 0x5E, 0x35, 0x60, 0x37, 0x1B,
+ 0x25, 0x05, 0x02, 0x57, 0x28, 0x5D, 0x37, 0x04, 0x02, 0x57, 0x28, 0xC2,
+ 0xA4, 0x25, 0x01, T0_INT2(BR_X509_BUFSIZE_SIG), 0x12, 0x06, 0x02, 0x50,
+ 0x28, 0x25, 0x5F, 0x35, 0x5C, 0xA5, 0x79, 0x79, 0x01, 0x00, 0x5B, 0x36,
+ 0x18, 0x00, 0x00, 0x01, 0x30, 0x0A, 0x25, 0x01, 0x00, 0x01, 0x09, 0x72,
+ 0x05, 0x02, 0x48, 0x28, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x01, 0x81,
+ 0x08, 0x00, 0x00, 0x01, 0x81, 0x10, 0x00, 0x00, 0x01, 0x81, 0x19, 0x00,
+ 0x00, 0x01, 0x81, 0x22, 0x00, 0x00, 0x01, 0x81, 0x2B, 0x00, 0x01, 0x7E,
+ 0x01, 0x01, 0x11, 0x3B, 0x01, 0x83, 0xFD, 0x7F, 0x11, 0x15, 0x06, 0x03,
+ 0x3B, 0x24, 0x00, 0x3B, 0x25, 0x03, 0x00, 0x25, 0xCA, 0x05, 0x04, 0x42,
+ 0x01, 0x00, 0x00, 0x25, 0x01, 0x81, 0x00, 0x0D, 0x06, 0x04, 0x96, 0x04,
+ 0x80, 0x49, 0x25, 0x01, 0x90, 0x00, 0x0D, 0x06, 0x0F, 0x01, 0x06, 0x14,
+ 0x01, 0x81, 0x40, 0x2F, 0x96, 0x02, 0x00, 0x01, 0x00, 0x97, 0x04, 0x33,
+ 0x25, 0x01, 0x83, 0xFF, 0x7F, 0x0D, 0x06, 0x14, 0x01, 0x0C, 0x14, 0x01,
+ 0x81, 0x60, 0x2F, 0x96, 0x02, 0x00, 0x01, 0x06, 0x97, 0x02, 0x00, 0x01,
+ 0x00, 0x97, 0x04, 0x17, 0x01, 0x12, 0x14, 0x01, 0x81, 0x70, 0x2F, 0x96,
+ 0x02, 0x00, 0x01, 0x0C, 0x97, 0x02, 0x00, 0x01, 0x06, 0x97, 0x02, 0x00,
+ 0x01, 0x00, 0x97, 0x00, 0x00, 0x01, 0x82, 0x15, 0x00, 0x00, 0x25, 0x01,
+ 0x83, 0xB0, 0x00, 0x01, 0x83, 0xB7, 0x7F, 0x72, 0x00, 0x00, 0x01, 0x81,
+ 0x34, 0x00, 0x00, 0x01, 0x80, 0x6B, 0x00, 0x00, 0x01, 0x81, 0x78, 0x00,
+ 0x00, 0x01, 0x3D, 0x00, 0x00, 0x01, 0x80, 0x43, 0x00, 0x00, 0x01, 0x80,
+ 0x4D, 0x00, 0x00, 0x01, 0x80, 0x57, 0x00, 0x00, 0x01, 0x80, 0x61, 0x00,
+ 0x00, 0x30, 0x11, 0x06, 0x04, 0x42, 0xAD, 0xC2, 0xB4, 0x00, 0x00, 0x01,
+ 0x82, 0x09, 0x00, 0x00, 0x01, 0x81, 0x6C, 0x00, 0x00, 0x25, 0x01, 0x83,
+ 0xB8, 0x00, 0x01, 0x83, 0xBF, 0x7F, 0x72, 0x00, 0x00, 0x01, 0x30, 0x62,
+ 0x37, 0x01, 0x7F, 0x7C, 0x19, 0x01, 0x00, 0x7C, 0x19, 0x04, 0x7A, 0x00,
+ 0x01, 0x81, 0x38, 0x00, 0x01, 0x7E, 0x0D, 0x06, 0x02, 0x4F, 0x28, 0x25,
+ 0x03, 0x00, 0x0A, 0x02, 0x00, 0x00, 0x00, 0x30, 0x25, 0x3F, 0x3B, 0x01,
+ 0x82, 0x00, 0x13, 0x2F, 0x06, 0x04, 0x42, 0x01, 0x00, 0x00, 0x30, 0x67,
+ 0x09, 0x37, 0x40, 0x00, 0x00, 0x14, 0x01, 0x3F, 0x15, 0x01, 0x81, 0x00,
+ 0x2F, 0x96, 0x00, 0x02, 0x01, 0x00, 0x03, 0x00, 0xAF, 0x25, 0x06, 0x80,
+ 0x59, 0xB3, 0x01, 0x20, 0x30, 0x11, 0x06, 0x17, 0x24, 0x74, 0xAD, 0x9E,
+ 0x24, 0x01, 0x7F, 0x2E, 0x03, 0x01, 0xB3, 0x01, 0x20, 0x77, 0xAD, 0xB2,
+ 0x02, 0x01, 0x1F, 0x79, 0x79, 0x04, 0x38, 0x01, 0x21, 0x30, 0x11, 0x06,
+ 0x08, 0x24, 0x75, 0xB6, 0x01, 0x01, 0x1E, 0x04, 0x2A, 0x01, 0x22, 0x30,
+ 0x11, 0x06, 0x11, 0x24, 0x75, 0xB6, 0x25, 0x06, 0x06, 0x2C, 0x02, 0x00,
+ 0x2F, 0x03, 0x00, 0x01, 0x02, 0x1E, 0x04, 0x13, 0x01, 0x26, 0x30, 0x11,
+ 0x06, 0x08, 0x24, 0x75, 0xB6, 0x01, 0x06, 0x1E, 0x04, 0x05, 0x42, 0xAE,
+ 0x01, 0x00, 0x24, 0x04, 0xFF, 0x23, 0x79, 0x02, 0x00, 0x00, 0x00, 0xAF,
+ 0xB4, 0x25, 0x01, 0x01, 0x11, 0x06, 0x08, 0xA6, 0x05, 0x02, 0x51, 0x28,
+ 0xB4, 0x04, 0x02, 0x51, 0x28, 0x25, 0x01, 0x02, 0x11, 0x06, 0x0C, 0x24,
+ 0x75, 0xB0, 0x66, 0x2B, 0x41, 0x0D, 0x06, 0x02, 0x51, 0x28, 0xB4, 0x01,
+ 0x7F, 0x10, 0x06, 0x02, 0x56, 0x28, 0x24, 0x79, 0x00, 0x00, 0xAF, 0x25,
+ 0x06, 0x1A, 0xAF, 0x9E, 0x24, 0x25, 0x06, 0x11, 0xAF, 0x25, 0x06, 0x0C,
+ 0xAF, 0x9E, 0x24, 0x89, 0x26, 0x05, 0x02, 0x49, 0x28, 0xC2, 0x04, 0x71,
+ 0x79, 0x79, 0x04, 0x63, 0x79, 0x00, 0x02, 0x03, 0x00, 0xB3, 0x01, 0x03,
+ 0x78, 0xAD, 0xBA, 0x03, 0x01, 0x02, 0x01, 0x01, 0x07, 0x12, 0x06, 0x02,
+ 0x56, 0x28, 0x25, 0x01, 0x00, 0x30, 0x11, 0x06, 0x05, 0x24, 0x4D, 0x28,
+ 0x04, 0x15, 0x01, 0x01, 0x30, 0x11, 0x06, 0x0A, 0x24, 0xBA, 0x02, 0x01,
+ 0x14, 0x02, 0x01, 0x0E, 0x04, 0x05, 0x24, 0xBA, 0x01, 0x00, 0x24, 0x02,
+ 0x00, 0x06, 0x19, 0x01, 0x00, 0x30, 0x01, 0x38, 0x15, 0x06, 0x03, 0x01,
+ 0x10, 0x2F, 0x3B, 0x01, 0x81, 0x40, 0x15, 0x06, 0x03, 0x01, 0x20, 0x2F,
+ 0x62, 0x37, 0x04, 0x07, 0x01, 0x04, 0x15, 0x05, 0x02, 0x4D, 0x28, 0xC2,
+ 0x00, 0x00, 0x38, 0xAF, 0xC2, 0x1A, 0x00, 0x03, 0x01, 0x00, 0x03, 0x00,
+ 0x38, 0xAF, 0x25, 0x06, 0x30, 0xB3, 0x01, 0x11, 0x77, 0xAD, 0x25, 0x05,
+ 0x02, 0x44, 0x28, 0x25, 0x06, 0x20, 0xAF, 0x9E, 0x24, 0x87, 0x26, 0x03,
+ 0x01, 0x01, 0x00, 0x2E, 0x03, 0x02, 0xB2, 0x25, 0x02, 0x01, 0x15, 0x06,
+ 0x07, 0x2C, 0x06, 0x04, 0x01, 0x7F, 0x03, 0x00, 0x02, 0x02, 0x1F, 0x79,
+ 0x04, 0x5D, 0x79, 0x04, 0x4D, 0x79, 0x1A, 0x02, 0x00, 0x00, 0x00, 0xB3,
+ 0x01, 0x06, 0x78, 0xB1, 0x00, 0x00, 0xB8, 0x86, 0x06, 0x0E, 0x3B, 0x25,
+ 0x05, 0x06, 0x42, 0x01, 0x00, 0x01, 0x00, 0x00, 0xB8, 0x6D, 0x04, 0x08,
+ 0x92, 0x06, 0x05, 0x24, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0xB9, 0x86,
+ 0x06, 0x0E, 0x3B, 0x25, 0x05, 0x06, 0x42, 0x01, 0x00, 0x01, 0x00, 0x00,
+ 0xB9, 0x6D, 0x04, 0x08, 0x92, 0x06, 0x05, 0x24, 0x01, 0x00, 0x04, 0x00,
+ 0x00, 0x00, 0xBA, 0x25, 0x01, 0x81, 0x00, 0x0D, 0x06, 0x04, 0x00, 0x04,
+ 0x80, 0x55, 0x25, 0x01, 0x81, 0x40, 0x0D, 0x06, 0x07, 0x24, 0x01, 0x00,
+ 0x00, 0x04, 0x80, 0x47, 0x25, 0x01, 0x81, 0x60, 0x0D, 0x06, 0x0E, 0x01,
+ 0x1F, 0x15, 0x01, 0x01, 0xA3, 0x01, 0x81, 0x00, 0x01, 0x8F, 0x7F, 0x04,
+ 0x32, 0x25, 0x01, 0x81, 0x70, 0x0D, 0x06, 0x0F, 0x01, 0x0F, 0x15, 0x01,
+ 0x02, 0xA3, 0x01, 0x90, 0x00, 0x01, 0x83, 0xFF, 0x7F, 0x04, 0x1C, 0x25,
+ 0x01, 0x81, 0x78, 0x0D, 0x06, 0x11, 0x01, 0x07, 0x15, 0x01, 0x03, 0xA3,
+ 0x01, 0x84, 0x80, 0x00, 0x01, 0x80, 0xC3, 0xFF, 0x7F, 0x04, 0x04, 0x24,
+ 0x01, 0x00, 0x00, 0x72, 0x05, 0x03, 0x24, 0x01, 0x00, 0x00, 0x00, 0x3B,
+ 0x25, 0x05, 0x06, 0x42, 0x01, 0x00, 0x01, 0x7F, 0x00, 0xBA, 0x34, 0x25,
+ 0x3D, 0x06, 0x03, 0x3B, 0x24, 0x00, 0x01, 0x06, 0x0E, 0x3B, 0x25, 0x01,
+ 0x06, 0x14, 0x01, 0x02, 0x10, 0x06, 0x04, 0x42, 0x01, 0x7F, 0x00, 0x01,
+ 0x3F, 0x15, 0x09, 0x00, 0x00, 0x25, 0x06, 0x06, 0x0B, 0xA2, 0x34, 0x41,
+ 0x04, 0x77, 0x24, 0x25, 0x00, 0x00, 0xB3, 0x01, 0x03, 0x78, 0xAD, 0xBA,
+ 0x06, 0x02, 0x55, 0x28, 0x00, 0x00, 0x3B, 0x25, 0x06, 0x07, 0x31, 0x25,
+ 0x06, 0x01, 0x19, 0x04, 0x76, 0x42, 0x00, 0x00, 0x01, 0x01, 0x78, 0xAC,
+ 0x01, 0x01, 0x10, 0x06, 0x02, 0x43, 0x28, 0xBA, 0x3E, 0x00, 0x04, 0xB3,
+ 0x25, 0x01, 0x17, 0x01, 0x18, 0x72, 0x05, 0x02, 0x48, 0x28, 0x01, 0x18,
+ 0x11, 0x03, 0x00, 0x75, 0xAD, 0xA8, 0x02, 0x00, 0x06, 0x0C, 0x01, 0x80,
+ 0x64, 0x08, 0x03, 0x01, 0xA8, 0x02, 0x01, 0x09, 0x04, 0x0E, 0x25, 0x01,
+ 0x32, 0x0D, 0x06, 0x04, 0x01, 0x80, 0x64, 0x09, 0x01, 0x8E, 0x6C, 0x09,
+ 0x03, 0x01, 0x02, 0x01, 0x01, 0x82, 0x6D, 0x08, 0x02, 0x01, 0x01, 0x03,
+ 0x09, 0x01, 0x04, 0x0C, 0x09, 0x02, 0x01, 0x01, 0x80, 0x63, 0x09, 0x01,
+ 0x80, 0x64, 0x0C, 0x0A, 0x02, 0x01, 0x01, 0x83, 0x0F, 0x09, 0x01, 0x83,
+ 0x10, 0x0C, 0x09, 0x03, 0x03, 0x01, 0x01, 0x01, 0x0C, 0xA9, 0x41, 0x01,
+ 0x01, 0x0E, 0x02, 0x01, 0x01, 0x04, 0x07, 0x3F, 0x02, 0x01, 0x01, 0x80,
+ 0x64, 0x07, 0x3E, 0x02, 0x01, 0x01, 0x83, 0x10, 0x07, 0x3F, 0x2F, 0x15,
+ 0x06, 0x03, 0x01, 0x18, 0x09, 0x94, 0x09, 0x7B, 0x25, 0x01, 0x05, 0x14,
+ 0x02, 0x03, 0x09, 0x03, 0x03, 0x01, 0x1F, 0x15, 0x01, 0x01, 0x3B, 0xA9,
+ 0x02, 0x03, 0x09, 0x41, 0x03, 0x03, 0x01, 0x00, 0x01, 0x17, 0xA9, 0x01,
+ 0x9C, 0x10, 0x08, 0x03, 0x02, 0x01, 0x00, 0x01, 0x3B, 0xA9, 0x01, 0x3C,
+ 0x08, 0x02, 0x02, 0x09, 0x03, 0x02, 0x01, 0x00, 0x01, 0x3C, 0xA9, 0x02,
+ 0x02, 0x09, 0x03, 0x02, 0xBA, 0x25, 0x01, 0x2E, 0x11, 0x06, 0x0D, 0x24,
+ 0xBA, 0x25, 0x01, 0x30, 0x01, 0x39, 0x72, 0x06, 0x03, 0x24, 0x04, 0x74,
+ 0x01, 0x80, 0x5A, 0x10, 0x06, 0x02, 0x48, 0x28, 0x79, 0x02, 0x03, 0x02,
+ 0x02, 0x00, 0x01, 0xBA, 0x7D, 0x01, 0x0A, 0x08, 0x03, 0x00, 0xBA, 0x7D,
+ 0x02, 0x00, 0x09, 0x00, 0x02, 0x03, 0x00, 0x03, 0x01, 0xA8, 0x25, 0x02,
+ 0x01, 0x02, 0x00, 0x72, 0x05, 0x02, 0x48, 0x28, 0x00, 0x00, 0x34, 0xB3,
+ 0x01, 0x02, 0x78, 0x0B, 0xAB, 0x00, 0x03, 0x25, 0x03, 0x00, 0x03, 0x01,
+ 0x03, 0x02, 0xAD, 0xBA, 0x25, 0x01, 0x81, 0x00, 0x13, 0x06, 0x02, 0x54,
+ 0x28, 0x25, 0x01, 0x00, 0x11, 0x06, 0x0B, 0x24, 0x25, 0x05, 0x04, 0x24,
+ 0x01, 0x00, 0x00, 0xBA, 0x04, 0x6F, 0x02, 0x01, 0x25, 0x05, 0x02, 0x50,
+ 0x28, 0x41, 0x03, 0x01, 0x02, 0x02, 0x37, 0x02, 0x02, 0x40, 0x03, 0x02,
+ 0x25, 0x06, 0x03, 0xBA, 0x04, 0x68, 0x24, 0x02, 0x00, 0x02, 0x01, 0x0A,
+ 0x00, 0x01, 0xBA, 0x25, 0x01, 0x81, 0x00, 0x0D, 0x06, 0x01, 0x00, 0x01,
+ 0x81, 0x00, 0x0A, 0x25, 0x05, 0x02, 0x4E, 0x28, 0x03, 0x00, 0x01, 0x00,
+ 0x02, 0x00, 0x01, 0x00, 0x12, 0x06, 0x19, 0x02, 0x00, 0x41, 0x03, 0x00,
+ 0x25, 0x01, 0x83, 0xFF, 0xFF, 0x7F, 0x12, 0x06, 0x02, 0x4F, 0x28, 0x01,
+ 0x08, 0x0E, 0x3B, 0xBA, 0x34, 0x09, 0x04, 0x60, 0x00, 0x00, 0xAC, 0x95,
+ 0x00, 0x00, 0xAD, 0xC2, 0x00, 0x00, 0xB3, 0x76, 0xAD, 0x00, 0x01, 0xAD,
+ 0x25, 0x05, 0x02, 0x54, 0x28, 0xBA, 0x25, 0x01, 0x81, 0x00, 0x13, 0x06,
+ 0x02, 0x54, 0x28, 0x03, 0x00, 0x25, 0x06, 0x16, 0xBA, 0x02, 0x00, 0x25,
+ 0x01, 0x87, 0xFF, 0xFF, 0x7F, 0x13, 0x06, 0x02, 0x54, 0x28, 0x01, 0x08,
+ 0x0E, 0x09, 0x03, 0x00, 0x04, 0x67, 0x24, 0x02, 0x00, 0x00, 0x00, 0xAD,
+ 0x25, 0x01, 0x81, 0x7F, 0x12, 0x06, 0x08, 0xC2, 0x01, 0x00, 0x67, 0x37,
+ 0x01, 0x00, 0x00, 0x25, 0x67, 0x37, 0x67, 0x40, 0xA5, 0x01, 0x7F, 0x00,
+ 0x00, 0xB3, 0x01, 0x0C, 0x30, 0x11, 0x06, 0x05, 0x24, 0x75, 0xB6, 0x04,
+ 0x3E, 0x01, 0x12, 0x30, 0x11, 0x06, 0x05, 0x24, 0x75, 0xB7, 0x04, 0x33,
+ 0x01, 0x13, 0x30, 0x11, 0x06, 0x05, 0x24, 0x75, 0xB7, 0x04, 0x28, 0x01,
+ 0x14, 0x30, 0x11, 0x06, 0x05, 0x24, 0x75, 0xB7, 0x04, 0x1D, 0x01, 0x16,
+ 0x30, 0x11, 0x06, 0x05, 0x24, 0x75, 0xB7, 0x04, 0x12, 0x01, 0x1E, 0x30,
+ 0x11, 0x06, 0x05, 0x24, 0x75, 0xB5, 0x04, 0x07, 0x42, 0xAE, 0x01, 0x00,
+ 0x01, 0x00, 0x24, 0x00, 0x01, 0xBA, 0x03, 0x00, 0x02, 0x00, 0x01, 0x05,
+ 0x14, 0x01, 0x01, 0x15, 0x2D, 0x02, 0x00, 0x01, 0x06, 0x14, 0x25, 0x01,
+ 0x01, 0x15, 0x06, 0x02, 0x46, 0x28, 0x01, 0x04, 0x0E, 0x02, 0x00, 0x01,
+ 0x1F, 0x15, 0x25, 0x01, 0x1F, 0x11, 0x06, 0x02, 0x47, 0x28, 0x09, 0x00,
+ 0x00, 0x25, 0x05, 0x05, 0x01, 0x00, 0x01, 0x7F, 0x00, 0xB3, 0x00, 0x01,
+ 0xAD, 0x25, 0x05, 0x05, 0x67, 0x37, 0x01, 0x7F, 0x00, 0x01, 0x01, 0x03,
+ 0x00, 0x9F, 0x25, 0x01, 0x83, 0xFF, 0x7E, 0x11, 0x06, 0x16, 0x24, 0x25,
+ 0x06, 0x10, 0xA0, 0x25, 0x05, 0x05, 0x24, 0xC2, 0x01, 0x00, 0x00, 0x02,
+ 0x00, 0x84, 0x03, 0x00, 0x04, 0x6D, 0x04, 0x1B, 0x25, 0x05, 0x05, 0x24,
+ 0xC2, 0x01, 0x00, 0x00, 0x02, 0x00, 0x84, 0x03, 0x00, 0x25, 0x06, 0x0B,
+ 0x9F, 0x25, 0x05, 0x05, 0x24, 0xC2, 0x01, 0x00, 0x00, 0x04, 0x6D, 0x24,
+ 0x02, 0x00, 0x25, 0x05, 0x01, 0x00, 0x41, 0x67, 0x37, 0x01, 0x7F, 0x00,
+ 0x01, 0xAD, 0x01, 0x01, 0x03, 0x00, 0x25, 0x06, 0x10, 0xA1, 0x25, 0x05,
+ 0x05, 0x24, 0xC2, 0x01, 0x00, 0x00, 0x02, 0x00, 0x84, 0x03, 0x00, 0x04,
+ 0x6D, 0x24, 0x02, 0x00, 0x25, 0x05, 0x01, 0x00, 0x41, 0x67, 0x37, 0x01,
+ 0x7F, 0x00, 0x01, 0xAD, 0x01, 0x01, 0x03, 0x00, 0x25, 0x06, 0x10, 0xBA,
+ 0x25, 0x05, 0x05, 0x24, 0xC2, 0x01, 0x00, 0x00, 0x02, 0x00, 0x84, 0x03,
+ 0x00, 0x04, 0x6D, 0x24, 0x02, 0x00, 0x25, 0x05, 0x01, 0x00, 0x41, 0x67,
+ 0x37, 0x01, 0x7F, 0x00, 0x00, 0xBA, 0x01, 0x08, 0x0E, 0x3B, 0xBA, 0x34,
+ 0x09, 0x00, 0x00, 0xBA, 0x3B, 0xBA, 0x01, 0x08, 0x0E, 0x34, 0x09, 0x00,
+ 0x00, 0x25, 0x05, 0x02, 0x4F, 0x28, 0x41, 0xBB, 0x00, 0x00, 0x32, 0x25,
+ 0x01, 0x00, 0x13, 0x06, 0x01, 0x00, 0x24, 0x19, 0x04, 0x74, 0x00, 0x01,
+ 0x01, 0x00, 0x00, 0x01, 0x0B, 0x00, 0x00, 0x01, 0x15, 0x00, 0x00, 0x01,
+ 0x1F, 0x00, 0x00, 0x01, 0x29, 0x00, 0x00, 0x01, 0x33, 0x00, 0x00, 0xC3,
+ 0x24, 0x00, 0x00, 0x25, 0x06, 0x07, 0xC4, 0x25, 0x06, 0x01, 0x19, 0x04,
+ 0x76, 0x00, 0x00, 0x01, 0x00, 0x30, 0x31, 0x0B, 0x42, 0x00, 0x00, 0x01,
+ 0x81, 0x70, 0x00, 0x00, 0x01, 0x82, 0x0D, 0x00, 0x00, 0x01, 0x82, 0x22,
+ 0x00, 0x00, 0x01, 0x82, 0x05, 0x00, 0x00, 0x01, 0x03, 0x33, 0x01, 0x03,
+ 0x33, 0x00, 0x00, 0x25, 0x01, 0x83, 0xFB, 0x50, 0x01, 0x83, 0xFD, 0x5F,
+ 0x72, 0x06, 0x04, 0x24, 0x01, 0x00, 0x00, 0x25, 0x01, 0x83, 0xB0, 0x00,
+ 0x01, 0x83, 0xBF, 0x7F, 0x72, 0x06, 0x04, 0x24, 0x01, 0x00, 0x00, 0x01,
+ 0x83, 0xFF, 0x7F, 0x15, 0x01, 0x83, 0xFF, 0x7E, 0x0D, 0x00
+};
+
+static const uint16_t t0_caddr[] = {
+ 0,
+ 5,
+ 10,
+ 15,
+ 20,
+ 25,
+ 29,
+ 33,
+ 37,
+ 41,
+ 45,
+ 49,
+ 53,
+ 57,
+ 61,
+ 65,
+ 69,
+ 73,
+ 77,
+ 81,
+ 85,
+ 89,
+ 93,
+ 97,
+ 101,
+ 105,
+ 109,
+ 113,
+ 117,
+ 121,
+ 125,
+ 130,
+ 135,
+ 140,
+ 145,
+ 150,
+ 155,
+ 160,
+ 165,
+ 173,
+ 178,
+ 183,
+ 188,
+ 193,
+ 198,
+ 202,
+ 207,
+ 212,
+ 217,
+ 238,
+ 243,
+ 248,
+ 253,
+ 282,
+ 297,
+ 302,
+ 308,
+ 314,
+ 319,
+ 327,
+ 335,
+ 341,
+ 346,
+ 357,
+ 992,
+ 1007,
+ 1011,
+ 1016,
+ 1021,
+ 1026,
+ 1031,
+ 1036,
+ 1150,
+ 1155,
+ 1167,
+ 1172,
+ 1177,
+ 1182,
+ 1186,
+ 1191,
+ 1196,
+ 1201,
+ 1206,
+ 1216,
+ 1221,
+ 1226,
+ 1238,
+ 1253,
+ 1258,
+ 1272,
+ 1294,
+ 1305,
+ 1408,
+ 1455,
+ 1488,
+ 1579,
+ 1585,
+ 1648,
+ 1655,
+ 1683,
+ 1711,
+ 1816,
+ 1858,
+ 1871,
+ 1883,
+ 1897,
+ 1912,
+ 2132,
+ 2146,
+ 2163,
+ 2172,
+ 2239,
+ 2295,
+ 2299,
+ 2303,
+ 2308,
+ 2356,
+ 2382,
+ 2458,
+ 2502,
+ 2513,
+ 2598,
+ 2636,
+ 2674,
+ 2684,
+ 2694,
+ 2703,
+ 2716,
+ 2720,
+ 2724,
+ 2728,
+ 2732,
+ 2736,
+ 2740,
+ 2744,
+ 2756,
+ 2764,
+ 2769,
+ 2774,
+ 2779,
+ 2784,
+ 2792
+};
+
+#define T0_INTERPRETED 61
+
+#define T0_ENTER(ip, rp, slot) do { \
+ const unsigned char *t0_newip; \
+ uint32_t t0_lnum; \
+ t0_newip = &t0_codeblock[t0_caddr[(slot) - T0_INTERPRETED]]; \
+ t0_lnum = t0_parse7E_unsigned(&t0_newip); \
+ (rp) += t0_lnum; \
+ *((rp) ++) = (uint32_t)((ip) - &t0_codeblock[0]) + (t0_lnum << 16); \
+ (ip) = t0_newip; \
+ } while (0)
+
+#define T0_DEFENTRY(name, slot) \
+void \
+name(void *ctx) \
+{ \
+ t0_context *t0ctx = ctx; \
+ t0ctx->ip = &t0_codeblock[0]; \
+ T0_ENTER(t0ctx->ip, t0ctx->rp, slot); \
+}
+
+T0_DEFENTRY(br_x509_minimal_init_main, 147)
+
+#define T0_NEXT(t0ipp) (*(*(t0ipp)) ++)
+
+void
+br_x509_minimal_run(void *t0ctx)
+{
+ uint32_t *dp, *rp;
+ const unsigned char *ip;
+
+#define T0_LOCAL(x) (*(rp - 2 - (x)))
+#define T0_POP() (*-- dp)
+#define T0_POPi() (*(int32_t *)(-- dp))
+#define T0_PEEK(x) (*(dp - 1 - (x)))
+#define T0_PEEKi(x) (*(int32_t *)(dp - 1 - (x)))
+#define T0_PUSH(v) do { *dp = (v); dp ++; } while (0)
+#define T0_PUSHi(v) do { *(int32_t *)dp = (v); dp ++; } while (0)
+#define T0_RPOP() (*-- rp)
+#define T0_RPOPi() (*(int32_t *)(-- rp))
+#define T0_RPUSH(v) do { *rp = (v); rp ++; } while (0)
+#define T0_RPUSHi(v) do { *(int32_t *)rp = (v); rp ++; } while (0)
+#define T0_ROLL(x) do { \
+ size_t t0len = (size_t)(x); \
+ uint32_t t0tmp = *(dp - 1 - t0len); \
+ memmove(dp - t0len - 1, dp - t0len, t0len * sizeof *dp); \
+ *(dp - 1) = t0tmp; \
+} while (0)
+#define T0_SWAP() do { \
+ uint32_t t0tmp = *(dp - 2); \
+ *(dp - 2) = *(dp - 1); \
+ *(dp - 1) = t0tmp; \
+} while (0)
+#define T0_ROT() do { \
+ uint32_t t0tmp = *(dp - 3); \
+ *(dp - 3) = *(dp - 2); \
+ *(dp - 2) = *(dp - 1); \
+ *(dp - 1) = t0tmp; \
+} while (0)
+#define T0_NROT() do { \
+ uint32_t t0tmp = *(dp - 1); \
+ *(dp - 1) = *(dp - 2); \
+ *(dp - 2) = *(dp - 3); \
+ *(dp - 3) = t0tmp; \
+} while (0)
+#define T0_PICK(x) do { \
+ uint32_t t0depth = (x); \
+ T0_PUSH(T0_PEEK(t0depth)); \
+} while (0)
+#define T0_CO() do { \
+ goto t0_exit; \
+} while (0)
+#define T0_RET() goto t0_next
+
+ dp = ((t0_context *)t0ctx)->dp;
+ rp = ((t0_context *)t0ctx)->rp;
+ ip = ((t0_context *)t0ctx)->ip;
+ goto t0_next;
+ for (;;) {
+ uint32_t t0x;
+
+ t0_next:
+ t0x = T0_NEXT(&ip);
+ if (t0x < T0_INTERPRETED) {
+ switch (t0x) {
+ int32_t t0off;
+
+ case 0: /* ret */
+ t0x = T0_RPOP();
+ rp -= (t0x >> 16);
+ t0x &= 0xFFFF;
+ if (t0x == 0) {
+ ip = NULL;
+ goto t0_exit;
+ }
+ ip = &t0_codeblock[t0x];
+ break;
+ case 1: /* literal constant */
+ T0_PUSHi(t0_parse7E_signed(&ip));
+ break;
+ case 2: /* read local */
+ T0_PUSH(T0_LOCAL(t0_parse7E_unsigned(&ip)));
+ break;
+ case 3: /* write local */
+ T0_LOCAL(t0_parse7E_unsigned(&ip)) = T0_POP();
+ break;
+ case 4: /* jump */
+ t0off = t0_parse7E_signed(&ip);
+ ip += t0off;
+ break;
+ case 5: /* jump if */
+ t0off = t0_parse7E_signed(&ip);
+ if (T0_POP()) {
+ ip += t0off;
+ }
+ break;
+ case 6: /* jump if not */
+ t0off = t0_parse7E_signed(&ip);
+ if (!T0_POP()) {
+ ip += t0off;
+ }
+ break;
+ case 7: {
+ /* %25 */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSHi(a % b);
+
+ }
+ break;
+ case 8: {
+ /* * */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a * b);
+
+ }
+ break;
+ case 9: {
+ /* + */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a + b);
+
+ }
+ break;
+ case 10: {
+ /* - */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a - b);
+
+ }
+ break;
+ case 11: {
+ /* -rot */
+ T0_NROT();
+ }
+ break;
+ case 12: {
+ /* / */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSHi(a / b);
+
+ }
+ break;
+ case 13: {
+ /* < */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a < b));
+
+ }
+ break;
+ case 14: {
+ /* << */
+
+ int c = (int)T0_POPi();
+ uint32_t x = T0_POP();
+ T0_PUSH(x << c);
+
+ }
+ break;
+ case 15: {
+ /* <= */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a <= b));
+
+ }
+ break;
+ case 16: {
+ /* <> */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(-(uint32_t)(a != b));
+
+ }
+ break;
+ case 17: {
+ /* = */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(-(uint32_t)(a == b));
+
+ }
+ break;
+ case 18: {
+ /* > */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a > b));
+
+ }
+ break;
+ case 19: {
+ /* >= */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a >= b));
+
+ }
+ break;
+ case 20: {
+ /* >> */
+
+ int c = (int)T0_POPi();
+ int32_t x = T0_POPi();
+ T0_PUSHi(x >> c);
+
+ }
+ break;
+ case 21: {
+ /* and */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a & b);
+
+ }
+ break;
+ case 22: {
+ /* blobcopy */
+
+ size_t len = T0_POP();
+ unsigned char *src = (unsigned char *)CTX + T0_POP();
+ unsigned char *dst = (unsigned char *)CTX + T0_POP();
+ memcpy(dst, src, len);
+
+ }
+ break;
+ case 23: {
+ /* check-direct-trust */
+
+ size_t u;
+
+ for (u = 0; u < CTX->trust_anchors_num; u ++) {
+ const br_x509_trust_anchor *ta;
+ unsigned char hashed_DN[64];
+ int kt;
+
+ ta = &CTX->trust_anchors[u];
+ if (ta->flags & BR_X509_TA_CA) {
+ continue;
+ }
+ hash_dn(CTX, ta->dn.data, ta->dn.len, hashed_DN);
+ if (memcmp(hashed_DN, CTX->current_dn_hash, DNHASH_LEN)) {
+ continue;
+ }
+ kt = CTX->pkey.key_type;
+ if ((ta->pkey.key_type & 0x0F) != kt) {
+ continue;
+ }
+ switch (kt) {
+
+ case BR_KEYTYPE_RSA:
+ if (!eqbigint(CTX->pkey.key.rsa.n,
+ CTX->pkey.key.rsa.nlen,
+ ta->pkey.key.rsa.n,
+ ta->pkey.key.rsa.nlen)
+ || !eqbigint(CTX->pkey.key.rsa.e,
+ CTX->pkey.key.rsa.elen,
+ ta->pkey.key.rsa.e,
+ ta->pkey.key.rsa.elen))
+ {
+ continue;
+ }
+ break;
+
+ case BR_KEYTYPE_EC:
+ if (CTX->pkey.key.ec.curve != ta->pkey.key.ec.curve
+ || CTX->pkey.key.ec.qlen != ta->pkey.key.ec.qlen
+ || memcmp(CTX->pkey.key.ec.q,
+ ta->pkey.key.ec.q,
+ ta->pkey.key.ec.qlen) != 0)
+ {
+ continue;
+ }
+ break;
+
+ default:
+ continue;
+ }
+
+ /*
+ * Direct trust match!
+ */
+ CTX->err = BR_ERR_X509_OK;
+ T0_CO();
+ }
+
+ }
+ break;
+ case 24: {
+ /* check-trust-anchor-CA */
+
+ size_t u;
+
+ for (u = 0; u < CTX->trust_anchors_num; u ++) {
+ const br_x509_trust_anchor *ta;
+ unsigned char hashed_DN[64];
+
+ ta = &CTX->trust_anchors[u];
+ if (!(ta->flags & BR_X509_TA_CA)) {
+ continue;
+ }
+ hash_dn(CTX, ta->dn.data, ta->dn.len, hashed_DN);
+ if (memcmp(hashed_DN, CTX->saved_dn_hash, DNHASH_LEN)) {
+ continue;
+ }
+ if (verify_signature(CTX, &ta->pkey) == 0) {
+ CTX->err = BR_ERR_X509_OK;
+ T0_CO();
+ }
+ }
+
+ }
+ break;
+ case 25: {
+ /* co */
+ T0_CO();
+ }
+ break;
+ case 26: {
+ /* compute-dn-hash */
+
+ CTX->dn_hash_impl->out(&CTX->dn_hash.vtable, CTX->current_dn_hash);
+ CTX->do_dn_hash = 0;
+
+ }
+ break;
+ case 27: {
+ /* compute-tbs-hash */
+
+ int id = T0_POPi();
+ size_t len;
+ len = br_multihash_out(&CTX->mhash, id, CTX->tbs_hash);
+ T0_PUSH(len);
+
+ }
+ break;
+ case 28: {
+ /* copy-ee-ec-pkey */
+
+ size_t qlen = T0_POP();
+ uint32_t curve = T0_POP();
+ memcpy(CTX->ee_pkey_data, CTX->pkey_data, qlen);
+ CTX->pkey.key_type = BR_KEYTYPE_EC;
+ CTX->pkey.key.ec.curve = curve;
+ CTX->pkey.key.ec.q = CTX->ee_pkey_data;
+ CTX->pkey.key.ec.qlen = qlen;
+
+ }
+ break;
+ case 29: {
+ /* copy-ee-rsa-pkey */
+
+ size_t elen = T0_POP();
+ size_t nlen = T0_POP();
+ memcpy(CTX->ee_pkey_data, CTX->pkey_data, nlen + elen);
+ CTX->pkey.key_type = BR_KEYTYPE_RSA;
+ CTX->pkey.key.rsa.n = CTX->ee_pkey_data;
+ CTX->pkey.key.rsa.nlen = nlen;
+ CTX->pkey.key.rsa.e = CTX->ee_pkey_data + nlen;
+ CTX->pkey.key.rsa.elen = elen;
+
+ }
+ break;
+ case 30: {
+ /* copy-name-SAN */
+
+ unsigned tag = T0_POP();
+ unsigned ok = T0_POP();
+ size_t u, len;
+
+ len = CTX->pad[0];
+ for (u = 0; u < CTX->num_name_elts; u ++) {
+ br_name_element *ne;
+
+ ne = &CTX->name_elts[u];
+ if (ne->status == 0 && ne->oid[0] == 0 && ne->oid[1] == tag) {
+ if (ok && ne->len > len) {
+ memcpy(ne->buf, CTX->pad + 1, len);
+ ne->buf[len] = 0;
+ ne->status = 1;
+ } else {
+ ne->status = -1;
+ }
+ break;
+ }
+ }
+
+ }
+ break;
+ case 31: {
+ /* copy-name-element */
+
+ size_t len;
+ int32_t off = T0_POPi();
+ int ok = T0_POPi();
+
+ if (off >= 0) {
+ br_name_element *ne = &CTX->name_elts[off];
+
+ if (ok) {
+ len = CTX->pad[0];
+ if (len < ne->len) {
+ memcpy(ne->buf, CTX->pad + 1, len);
+ ne->buf[len] = 0;
+ ne->status = 1;
+ } else {
+ ne->status = -1;
+ }
+ } else {
+ ne->status = -1;
+ }
+ }
+
+ }
+ break;
+ case 32: {
+ /* data-get8 */
+
+ size_t addr = T0_POP();
+ T0_PUSH(t0_datablock[addr]);
+
+ }
+ break;
+ case 33: {
+ /* dn-hash-length */
+
+ T0_PUSH(DNHASH_LEN);
+
+ }
+ break;
+ case 34: {
+ /* do-ecdsa-vrfy */
+
+ size_t qlen = T0_POP();
+ int curve = T0_POP();
+ br_x509_pkey pk;
+
+ pk.key_type = BR_KEYTYPE_EC;
+ pk.key.ec.curve = curve;
+ pk.key.ec.q = CTX->pkey_data;
+ pk.key.ec.qlen = qlen;
+ T0_PUSH(verify_signature(CTX, &pk));
+
+ }
+ break;
+ case 35: {
+ /* do-rsa-vrfy */
+
+ size_t elen = T0_POP();
+ size_t nlen = T0_POP();
+ br_x509_pkey pk;
+
+ pk.key_type = BR_KEYTYPE_RSA;
+ pk.key.rsa.n = CTX->pkey_data;
+ pk.key.rsa.nlen = nlen;
+ pk.key.rsa.e = CTX->pkey_data + nlen;
+ pk.key.rsa.elen = elen;
+ T0_PUSH(verify_signature(CTX, &pk));
+
+ }
+ break;
+ case 36: {
+ /* drop */
+ (void)T0_POP();
+ }
+ break;
+ case 37: {
+ /* dup */
+ T0_PUSH(T0_PEEK(0));
+ }
+ break;
+ case 38: {
+ /* eqOID */
+
+ const unsigned char *a2 = &t0_datablock[T0_POP()];
+ const unsigned char *a1 = &CTX->pad[0];
+ size_t len = a1[0];
+ int x;
+ if (len == a2[0]) {
+ x = -(memcmp(a1 + 1, a2 + 1, len) == 0);
+ } else {
+ x = 0;
+ }
+ T0_PUSH((uint32_t)x);
+
+ }
+ break;
+ case 39: {
+ /* eqblob */
+
+ size_t len = T0_POP();
+ const unsigned char *a2 = (const unsigned char *)CTX + T0_POP();
+ const unsigned char *a1 = (const unsigned char *)CTX + T0_POP();
+ T0_PUSHi(-(memcmp(a1, a2, len) == 0));
+
+ }
+ break;
+ case 40: {
+ /* fail */
+
+ CTX->err = T0_POPi();
+ T0_CO();
+
+ }
+ break;
+ case 41: {
+ /* get-system-date */
+
+ if (CTX->days == 0 && CTX->seconds == 0) {
+#if BR_USE_UNIX_TIME
+ time_t x = time(NULL);
+
+ T0_PUSH((uint32_t)(x / 86400) + 719528);
+ T0_PUSH((uint32_t)(x % 86400));
+#elif BR_USE_WIN32_TIME
+ FILETIME ft;
+ uint64_t x;
+
+ GetSystemTimeAsFileTime(&ft);
+ x = ((uint64_t)ft.dwHighDateTime << 32)
+ + (uint64_t)ft.dwLowDateTime;
+ x = (x / 10000000);
+ T0_PUSH((uint32_t)(x / 86400) + 584754);
+ T0_PUSH((uint32_t)(x % 86400));
+#else
+ CTX->err = BR_ERR_X509_TIME_UNKNOWN;
+ T0_CO();
+#endif
+ } else {
+ T0_PUSH(CTX->days);
+ T0_PUSH(CTX->seconds);
+ }
+
+ }
+ break;
+ case 42: {
+ /* get16 */
+
+ uint32_t addr = T0_POP();
+ T0_PUSH(*(uint16_t *)(void *)((unsigned char *)CTX + addr));
+
+ }
+ break;
+ case 43: {
+ /* get32 */
+
+ uint32_t addr = T0_POP();
+ T0_PUSH(*(uint32_t *)(void *)((unsigned char *)CTX + addr));
+
+ }
+ break;
+ case 44: {
+ /* match-server-name */
+
+ size_t n1, n2;
+
+ if (CTX->server_name == NULL) {
+ T0_PUSH(0);
+ T0_RET();
+ }
+ n1 = strlen(CTX->server_name);
+ n2 = CTX->pad[0];
+ if (n1 == n2 && eqnocase(&CTX->pad[1], CTX->server_name, n1)) {
+ T0_PUSHi(-1);
+ T0_RET();
+ }
+ if (n2 >= 2 && CTX->pad[1] == '*' && CTX->pad[2] == '.') {
+ size_t u;
+
+ u = 0;
+ while (u < n1 && CTX->server_name[u] != '.') {
+ u ++;
+ }
+ u ++;
+ n1 -= u;
+ if ((n2 - 2) == n1
+ && eqnocase(&CTX->pad[3], CTX->server_name + u, n1))
+ {
+ T0_PUSHi(-1);
+ T0_RET();
+ }
+ }
+ T0_PUSH(0);
+
+ }
+ break;
+ case 45: {
+ /* neg */
+
+ uint32_t a = T0_POP();
+ T0_PUSH(-a);
+
+ }
+ break;
+ case 46: {
+ /* offset-name-element */
+
+ unsigned san = T0_POP();
+ size_t u;
+
+ for (u = 0; u < CTX->num_name_elts; u ++) {
+ if (CTX->name_elts[u].status == 0) {
+ const unsigned char *oid;
+ size_t len, off;
+
+ oid = CTX->name_elts[u].oid;
+ if (san) {
+ if (oid[0] != 0 || oid[1] != 0) {
+ continue;
+ }
+ off = 2;
+ } else {
+ off = 0;
+ }
+ len = oid[off];
+ if (len != 0 && len == CTX->pad[0]
+ && memcmp(oid + off + 1,
+ CTX->pad + 1, len) == 0)
+ {
+ T0_PUSH(u);
+ T0_RET();
+ }
+ }
+ }
+ T0_PUSHi(-1);
+
+ }
+ break;
+ case 47: {
+ /* or */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a | b);
+
+ }
+ break;
+ case 48: {
+ /* over */
+ T0_PUSH(T0_PEEK(1));
+ }
+ break;
+ case 49: {
+ /* read-blob-inner */
+
+ uint32_t len = T0_POP();
+ uint32_t addr = T0_POP();
+ size_t clen = CTX->hlen;
+ if (clen > len) {
+ clen = (size_t)len;
+ }
+ if (addr != 0) {
+ memcpy((unsigned char *)CTX + addr, CTX->hbuf, clen);
+ }
+ if (CTX->do_mhash) {
+ br_multihash_update(&CTX->mhash, CTX->hbuf, clen);
+ }
+ if (CTX->do_dn_hash) {
+ CTX->dn_hash_impl->update(
+ &CTX->dn_hash.vtable, CTX->hbuf, clen);
+ }
+ CTX->hbuf += clen;
+ CTX->hlen -= clen;
+ T0_PUSH(addr + clen);
+ T0_PUSH(len - clen);
+
+ }
+ break;
+ case 50: {
+ /* read8-low */
+
+ if (CTX->hlen == 0) {
+ T0_PUSHi(-1);
+ } else {
+ unsigned char x = *CTX->hbuf ++;
+ if (CTX->do_mhash) {
+ br_multihash_update(&CTX->mhash, &x, 1);
+ }
+ if (CTX->do_dn_hash) {
+ CTX->dn_hash_impl->update(&CTX->dn_hash.vtable, &x, 1);
+ }
+ CTX->hlen --;
+ T0_PUSH(x);
+ }
+
+ }
+ break;
+ case 51: {
+ /* roll */
+ T0_ROLL(T0_POP());
+ }
+ break;
+ case 52: {
+ /* rot */
+ T0_ROT();
+ }
+ break;
+ case 53: {
+ /* set16 */
+
+ uint32_t addr = T0_POP();
+ *(uint16_t *)(void *)((unsigned char *)CTX + addr) = T0_POP();
+
+ }
+ break;
+ case 54: {
+ /* set32 */
+
+ uint32_t addr = T0_POP();
+ *(uint32_t *)(void *)((unsigned char *)CTX + addr) = T0_POP();
+
+ }
+ break;
+ case 55: {
+ /* set8 */
+
+ uint32_t addr = T0_POP();
+ *((unsigned char *)CTX + addr) = (unsigned char)T0_POP();
+
+ }
+ break;
+ case 56: {
+ /* start-dn-hash */
+
+ CTX->dn_hash_impl->init(&CTX->dn_hash.vtable);
+ CTX->do_dn_hash = 1;
+
+ }
+ break;
+ case 57: {
+ /* start-tbs-hash */
+
+ br_multihash_init(&CTX->mhash);
+ CTX->do_mhash = 1;
+
+ }
+ break;
+ case 58: {
+ /* stop-tbs-hash */
+
+ CTX->do_mhash = 0;
+
+ }
+ break;
+ case 59: {
+ /* swap */
+ T0_SWAP();
+ }
+ break;
+ case 60: {
+ /* zero-server-name */
+
+ T0_PUSHi(-(CTX->server_name == NULL));
+
+ }
+ break;
+ }
+
+ } else {
+ T0_ENTER(ip, rp, t0x);
+ }
+ }
+t0_exit:
+ ((t0_context *)t0ctx)->dp = dp;
+ ((t0_context *)t0ctx)->rp = rp;
+ ((t0_context *)t0ctx)->ip = ip;
+}
+
+
+
+/*
+ * Verify the signature on the certificate with the provided public key.
+ * This function checks the public key type with regards to the expected
+ * type. Returned value is either 0 on success, or a non-zero error code.
+ */
+static int
+verify_signature(br_x509_minimal_context *ctx, const br_x509_pkey *pk)
+{
+ int kt;
+
+ kt = ctx->cert_signer_key_type;
+ if ((pk->key_type & 0x0F) != kt) {
+ return BR_ERR_X509_WRONG_KEY_TYPE;
+ }
+ switch (kt) {
+ unsigned char tmp[64];
+
+ case BR_KEYTYPE_RSA:
+ if (ctx->irsa == 0) {
+ return BR_ERR_X509_UNSUPPORTED;
+ }
+ if (!ctx->irsa(ctx->cert_sig, ctx->cert_sig_len,
+ &t0_datablock[ctx->cert_sig_hash_oid],
+ ctx->cert_sig_hash_len, &pk->key.rsa, tmp))
+ {
+ return BR_ERR_X509_BAD_SIGNATURE;
+ }
+ if (memcmp(ctx->tbs_hash, tmp, ctx->cert_sig_hash_len) != 0) {
+ return BR_ERR_X509_BAD_SIGNATURE;
+ }
+ return 0;
+
+ case BR_KEYTYPE_EC:
+ if (ctx->iecdsa == 0) {
+ return BR_ERR_X509_UNSUPPORTED;
+ }
+ if (!ctx->iecdsa(ctx->iec, ctx->tbs_hash,
+ ctx->cert_sig_hash_len, &pk->key.ec,
+ ctx->cert_sig, ctx->cert_sig_len))
+ {
+ return BR_ERR_X509_BAD_SIGNATURE;
+ }
+ return 0;
+
+ default:
+ return BR_ERR_X509_UNSUPPORTED;
+ }
+}
+
+
diff --git a/test/monniaux/BearSSL/src/x509/x509_minimal.t0 b/test/monniaux/BearSSL/src/x509/x509_minimal.t0
new file mode 100644
index 00000000..1e60016d
--- /dev/null
+++ b/test/monniaux/BearSSL/src/x509/x509_minimal.t0
@@ -0,0 +1,1508 @@
+\ Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+\
+\ Permission is hereby granted, free of charge, to any person obtaining
+\ a copy of this software and associated documentation files (the
+\ "Software"), to deal in the Software without restriction, including
+\ without limitation the rights to use, copy, modify, merge, publish,
+\ distribute, sublicense, and/or sell copies of the Software, and to
+\ permit persons to whom the Software is furnished to do so, subject to
+\ the following conditions:
+\
+\ The above copyright notice and this permission notice shall be
+\ included in all copies or substantial portions of the Software.
+\
+\ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+\ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+\ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+\ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+\ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+\ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+\ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+\ SOFTWARE.
+
+preamble {
+
+#include "inner.h"
+
+/*
+ * Implementation Notes
+ * --------------------
+ *
+ * The C code pushes the data by chunks; all decoding is done in the
+ * T0 code. The cert_length value is set to the certificate length when
+ * a new certificate is started; the T0 code picks it up as outer limit,
+ * and decoding functions use it to ensure that no attempt is made at
+ * reading past it. The T0 code also checks that once the certificate is
+ * decoded, there are no trailing bytes.
+ *
+ * The T0 code sets cert_length to 0 when the certificate is fully
+ * decoded.
+ *
+ * The C code must still perform two checks:
+ *
+ * -- If the certificate length is 0, then the T0 code will not be
+ * invoked at all. This invalid condition must thus be reported by the
+ * C code.
+ *
+ * -- When reaching the end of certificate, the C code must verify that
+ * the certificate length has been set to 0, thereby signaling that
+ * the T0 code properly decoded a certificate.
+ *
+ * Processing of a chain works in the following way:
+ *
+ * -- The error flag is set to a non-zero value when validation is
+ * finished. The value is either BR_ERR_X509_OK (validation is
+ * successful) or another non-zero error code. When a non-zero error
+ * code is obtained, the remaining bytes in the current certificate and
+ * the subsequent certificates (if any) are completely ignored.
+ *
+ * -- Each certificate is decoded in due course, with the following
+ * "interesting points":
+ *
+ * -- Start of the TBS: the multihash engine is reset and activated.
+ *
+ * -- Start of the issuer DN: the secondary hash engine is started,
+ * to process the encoded issuer DN.
+ *
+ * -- End of the issuer DN: the secondary hash engine is stopped. The
+ * resulting hash value is computed and then copied into the
+ * next_dn_hash[] buffer.
+ *
+ * -- Start of the subject DN: the secondary hash engine is started,
+ * to process the encoded subject DN.
+ *
+ * -- For the EE certificate only: the Common Name, if any, is matched
+ * against the expected server name.
+ *
+ * -- End of the subject DN: the secondary hash engine is stopped. The
+ * resulting hash value is computed into the pad. It is then processed:
+ *
+ * -- If this is the EE certificate, then the hash is ignored
+ * (except for direct trust processing, see later; the hash is
+ * simply left in current_dn_hash[]).
+ *
+ * -- Otherwise, the hashed subject DN is compared with the saved
+ * hash value (in saved_dn_hash[]). They must match.
+ *
+ * Either way, the next_dn_hash[] value is then copied into the
+ * saved_dn_hash[] value. Thus, at that point, saved_dn_hash[]
+ * contains the hash of the issuer DN for the current certificate,
+ * and current_dn_hash[] contains the hash of the subject DN for the
+ * current certificate.
+ *
+ * -- Public key: it is decoded into the cert_pkey[] buffer. Unknown
+ * key types are reported at that point.
+ *
+ * -- If this is the EE certificate, then the key type is compared
+ * with the expected key type (initialization parameter). The public
+ * key data is copied to ee_pkey_data[]. The key and hashed subject
+ * DN are also compared with the "direct trust" keys; if the key
+ * and DN are matched, then validation ends with a success.
+ *
+ * -- Otherwise, the saved signature (cert_sig[]) is verified
+ * against the saved TBS hash (tbs_hash[]) and that freshly
+ * decoded public key. Failure here ends validation with an error.
+ *
+ * -- Extensions: extension values are processed in due order.
+ *
+ * -- Basic Constraints: for all certificates except EE, must be
+ * present, indicate a CA, and have a path legnth compatible with
+ * the chain length so far.
+ *
+ * -- Key Usage: for the EE, if present, must allow signatures
+ * or encryption/key exchange, as required for the cipher suite.
+ * For non-EE, if present, must have the "certificate sign" bit.
+ *
+ * -- Subject Alt Name: for the EE, dNSName names are matched
+ * against the server name. Ignored for non-EE.
+ *
+ * -- Authority Key Identifier, Subject Key Identifier, Issuer
+ * Alt Name, Subject Directory Attributes, CRL Distribution Points
+ * Freshest CRL, Authority Info Access and Subject Info Access
+ * extensions are always ignored: they either contain only
+ * informative data, or they relate to revocation processing, which
+ * we explicitly do not support.
+ *
+ * -- All other extensions are ignored if non-critical. If a
+ * critical extension other than the ones above is encountered,
+ * then a failure is reported.
+ *
+ * -- End of the TBS: the multihash engine is stopped.
+ *
+ * -- Signature algorithm: the signature algorithm on the
+ * certificate is decoded. A failure is reported if that algorithm
+ * is unknown. The hashed TBS corresponding to the signature hash
+ * function is computed and stored in tbs_hash[] (if not supported,
+ * then a failure is reported). The hash OID and length are stored
+ * in cert_sig_hash_oid and cert_sig_hash_len.
+ *
+ * -- Signature value: the signature value is copied into the
+ * cert_sig[] array.
+ *
+ * -- Certificate end: the hashed issuer DN (saved_dn_hash[]) is
+ * looked up in the trust store (CA trust anchors only); for all
+ * that match, the signature (cert_sig[]) is verified against the
+ * anchor public key (hashed TBS is in tbs_hash[]). If one of these
+ * signatures is valid, then validation ends with a success.
+ *
+ * -- If the chain end is reached without obtaining a validation success,
+ * then validation is reported as failed.
+ */
+
+#if BR_USE_UNIX_TIME
+#include <time.h>
+#endif
+
+#if BR_USE_WIN32_TIME
+#include <windows.h>
+#endif
+
+/*
+ * The T0 compiler will produce these prototypes declarations in the
+ * header.
+ *
+void br_x509_minimal_init_main(void *ctx);
+void br_x509_minimal_run(void *ctx);
+ */
+
+/* see bearssl_x509.h */
+void
+br_x509_minimal_init(br_x509_minimal_context *ctx,
+ const br_hash_class *dn_hash_impl,
+ const br_x509_trust_anchor *trust_anchors, size_t trust_anchors_num)
+{
+ memset(ctx, 0, sizeof *ctx);
+ ctx->vtable = &br_x509_minimal_vtable;
+ ctx->dn_hash_impl = dn_hash_impl;
+ ctx->trust_anchors = trust_anchors;
+ ctx->trust_anchors_num = trust_anchors_num;
+}
+
+static void
+xm_start_chain(const br_x509_class **ctx, const char *server_name)
+{
+ br_x509_minimal_context *cc;
+ size_t u;
+
+ cc = (br_x509_minimal_context *)(void *)ctx;
+ for (u = 0; u < cc->num_name_elts; u ++) {
+ cc->name_elts[u].status = 0;
+ cc->name_elts[u].buf[0] = 0;
+ }
+ memset(&cc->pkey, 0, sizeof cc->pkey);
+ cc->num_certs = 0;
+ cc->err = 0;
+ cc->cpu.dp = cc->dp_stack;
+ cc->cpu.rp = cc->rp_stack;
+ br_x509_minimal_init_main(&cc->cpu);
+ if (server_name == NULL || *server_name == 0) {
+ cc->server_name = NULL;
+ } else {
+ cc->server_name = server_name;
+ }
+}
+
+static void
+xm_start_cert(const br_x509_class **ctx, uint32_t length)
+{
+ br_x509_minimal_context *cc;
+
+ cc = (br_x509_minimal_context *)(void *)ctx;
+ if (cc->err != 0) {
+ return;
+ }
+ if (length == 0) {
+ cc->err = BR_ERR_X509_TRUNCATED;
+ return;
+ }
+ cc->cert_length = length;
+}
+
+static void
+xm_append(const br_x509_class **ctx, const unsigned char *buf, size_t len)
+{
+ br_x509_minimal_context *cc;
+
+ cc = (br_x509_minimal_context *)(void *)ctx;
+ if (cc->err != 0) {
+ return;
+ }
+ cc->hbuf = buf;
+ cc->hlen = len;
+ br_x509_minimal_run(&cc->cpu);
+}
+
+static void
+xm_end_cert(const br_x509_class **ctx)
+{
+ br_x509_minimal_context *cc;
+
+ cc = (br_x509_minimal_context *)(void *)ctx;
+ if (cc->err == 0 && cc->cert_length != 0) {
+ cc->err = BR_ERR_X509_TRUNCATED;
+ }
+ cc->num_certs ++;
+}
+
+static unsigned
+xm_end_chain(const br_x509_class **ctx)
+{
+ br_x509_minimal_context *cc;
+
+ cc = (br_x509_minimal_context *)(void *)ctx;
+ if (cc->err == 0) {
+ if (cc->num_certs == 0) {
+ cc->err = BR_ERR_X509_EMPTY_CHAIN;
+ } else {
+ cc->err = BR_ERR_X509_NOT_TRUSTED;
+ }
+ } else if (cc->err == BR_ERR_X509_OK) {
+ return 0;
+ }
+ return (unsigned)cc->err;
+}
+
+static const br_x509_pkey *
+xm_get_pkey(const br_x509_class *const *ctx, unsigned *usages)
+{
+ br_x509_minimal_context *cc;
+
+ cc = (br_x509_minimal_context *)(void *)ctx;
+ if (cc->err == BR_ERR_X509_OK
+ || cc->err == BR_ERR_X509_NOT_TRUSTED)
+ {
+ if (usages != NULL) {
+ *usages = cc->key_usages;
+ }
+ return &((br_x509_minimal_context *)(void *)ctx)->pkey;
+ } else {
+ return NULL;
+ }
+}
+
+/* see bearssl_x509.h */
+const br_x509_class br_x509_minimal_vtable = {
+ sizeof(br_x509_minimal_context),
+ xm_start_chain,
+ xm_start_cert,
+ xm_append,
+ xm_end_cert,
+ xm_end_chain,
+ xm_get_pkey
+};
+
+#define CTX ((br_x509_minimal_context *)(void *)((unsigned char *)t0ctx - offsetof(br_x509_minimal_context, cpu)))
+#define CONTEXT_NAME br_x509_minimal_context
+
+#define DNHASH_LEN ((CTX->dn_hash_impl->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK)
+
+/*
+ * Hash a DN (from a trust anchor) into the provided buffer. This uses the
+ * DN hash implementation and context structure from the X.509 engine
+ * context.
+ */
+static void
+hash_dn(br_x509_minimal_context *ctx, const void *dn, size_t len,
+ unsigned char *out)
+{
+ ctx->dn_hash_impl->init(&ctx->dn_hash.vtable);
+ ctx->dn_hash_impl->update(&ctx->dn_hash.vtable, dn, len);
+ ctx->dn_hash_impl->out(&ctx->dn_hash.vtable, out);
+}
+
+/*
+ * Compare two big integers for equality. The integers use unsigned big-endian
+ * encoding; extra leading bytes (of value 0) are allowed.
+ */
+static int
+eqbigint(const unsigned char *b1, size_t len1,
+ const unsigned char *b2, size_t len2)
+{
+ while (len1 > 0 && *b1 == 0) {
+ b1 ++;
+ len1 --;
+ }
+ while (len2 > 0 && *b2 == 0) {
+ b2 ++;
+ len2 --;
+ }
+ if (len1 != len2) {
+ return 0;
+ }
+ return memcmp(b1, b2, len1) == 0;
+}
+
+/*
+ * Compare two strings for equality, in a case-insensitive way. This
+ * function handles casing only for ASCII letters.
+ */
+static int
+eqnocase(const void *s1, const void *s2, size_t len)
+{
+ const unsigned char *buf1, *buf2;
+
+ buf1 = s1;
+ buf2 = s2;
+ while (len -- > 0) {
+ int x1, x2;
+
+ x1 = *buf1 ++;
+ x2 = *buf2 ++;
+ if (x1 >= 'A' && x1 <= 'Z') {
+ x1 += 'a' - 'A';
+ }
+ if (x2 >= 'A' && x2 <= 'Z') {
+ x2 += 'a' - 'A';
+ }
+ if (x1 != x2) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static int verify_signature(br_x509_minimal_context *ctx,
+ const br_x509_pkey *pk);
+
+}
+
+postamble {
+
+/*
+ * Verify the signature on the certificate with the provided public key.
+ * This function checks the public key type with regards to the expected
+ * type. Returned value is either 0 on success, or a non-zero error code.
+ */
+static int
+verify_signature(br_x509_minimal_context *ctx, const br_x509_pkey *pk)
+{
+ int kt;
+
+ kt = ctx->cert_signer_key_type;
+ if ((pk->key_type & 0x0F) != kt) {
+ return BR_ERR_X509_WRONG_KEY_TYPE;
+ }
+ switch (kt) {
+ unsigned char tmp[64];
+
+ case BR_KEYTYPE_RSA:
+ if (ctx->irsa == 0) {
+ return BR_ERR_X509_UNSUPPORTED;
+ }
+ if (!ctx->irsa(ctx->cert_sig, ctx->cert_sig_len,
+ &t0_datablock[ctx->cert_sig_hash_oid],
+ ctx->cert_sig_hash_len, &pk->key.rsa, tmp))
+ {
+ return BR_ERR_X509_BAD_SIGNATURE;
+ }
+ if (memcmp(ctx->tbs_hash, tmp, ctx->cert_sig_hash_len) != 0) {
+ return BR_ERR_X509_BAD_SIGNATURE;
+ }
+ return 0;
+
+ case BR_KEYTYPE_EC:
+ if (ctx->iecdsa == 0) {
+ return BR_ERR_X509_UNSUPPORTED;
+ }
+ if (!ctx->iecdsa(ctx->iec, ctx->tbs_hash,
+ ctx->cert_sig_hash_len, &pk->key.ec,
+ ctx->cert_sig, ctx->cert_sig_len))
+ {
+ return BR_ERR_X509_BAD_SIGNATURE;
+ }
+ return 0;
+
+ default:
+ return BR_ERR_X509_UNSUPPORTED;
+ }
+}
+
+}
+
+cc: read8-low ( -- x ) {
+ if (CTX->hlen == 0) {
+ T0_PUSHi(-1);
+ } else {
+ unsigned char x = *CTX->hbuf ++;
+ if (CTX->do_mhash) {
+ br_multihash_update(&CTX->mhash, &x, 1);
+ }
+ if (CTX->do_dn_hash) {
+ CTX->dn_hash_impl->update(&CTX->dn_hash.vtable, &x, 1);
+ }
+ CTX->hlen --;
+ T0_PUSH(x);
+ }
+}
+
+addr: cert_length
+addr: num_certs
+
+cc: read-blob-inner ( addr len -- addr len ) {
+ uint32_t len = T0_POP();
+ uint32_t addr = T0_POP();
+ size_t clen = CTX->hlen;
+ if (clen > len) {
+ clen = (size_t)len;
+ }
+ if (addr != 0) {
+ memcpy((unsigned char *)CTX + addr, CTX->hbuf, clen);
+ }
+ if (CTX->do_mhash) {
+ br_multihash_update(&CTX->mhash, CTX->hbuf, clen);
+ }
+ if (CTX->do_dn_hash) {
+ CTX->dn_hash_impl->update(
+ &CTX->dn_hash.vtable, CTX->hbuf, clen);
+ }
+ CTX->hbuf += clen;
+ CTX->hlen -= clen;
+ T0_PUSH(addr + clen);
+ T0_PUSH(len - clen);
+}
+
+\ Compute the TBS hash, using the provided hash ID. The hash value is
+\ written in the tbs_hash[] array, and the hash length is returned. If
+\ the requested hash function is not supported, then 0 is returned.
+cc: compute-tbs-hash ( id -- hashlen ) {
+ int id = T0_POPi();
+ size_t len;
+ len = br_multihash_out(&CTX->mhash, id, CTX->tbs_hash);
+ T0_PUSH(len);
+}
+
+\ Push true (-1) if no server name is expected in the EE certificate.
+cc: zero-server-name ( -- bool ) {
+ T0_PUSHi(-(CTX->server_name == NULL));
+}
+
+addr: key_usages
+addr: cert_sig
+addr: cert_sig_len
+addr: cert_signer_key_type
+addr: cert_sig_hash_oid
+addr: cert_sig_hash_len
+addr: tbs_hash
+addr: min_rsa_size
+
+\ Start TBS hash computation. The hash functions are reinitialised.
+cc: start-tbs-hash ( -- ) {
+ br_multihash_init(&CTX->mhash);
+ CTX->do_mhash = 1;
+}
+
+\ Stop TBS hash computation.
+cc: stop-tbs-hash ( -- ) {
+ CTX->do_mhash = 0;
+}
+
+\ Start DN hash computation.
+cc: start-dn-hash ( -- ) {
+ CTX->dn_hash_impl->init(&CTX->dn_hash.vtable);
+ CTX->do_dn_hash = 1;
+}
+
+\ Terminate DN hash computation and write the DN hash into the
+\ current_dn_hash buffer.
+cc: compute-dn-hash ( -- ) {
+ CTX->dn_hash_impl->out(&CTX->dn_hash.vtable, CTX->current_dn_hash);
+ CTX->do_dn_hash = 0;
+}
+
+\ Get the length of hash values obtained with the DN hasher.
+cc: dn-hash-length ( -- len ) {
+ T0_PUSH(DNHASH_LEN);
+}
+
+\ Copy data between two areas in the context.
+cc: blobcopy ( addr-dst addr-src len -- ) {
+ size_t len = T0_POP();
+ unsigned char *src = (unsigned char *)CTX + T0_POP();
+ unsigned char *dst = (unsigned char *)CTX + T0_POP();
+ memcpy(dst, src, len);
+}
+
+addr: current_dn_hash
+addr: next_dn_hash
+addr: saved_dn_hash
+
+\ Read a DN, hashing it into current_dn_hash. The DN contents are not
+\ inspected (only the outer tag, for SEQUENCE, is checked).
+: read-DN ( lim -- lim )
+ start-dn-hash
+ read-sequence-open skip-close-elt
+ compute-dn-hash ;
+
+cc: offset-name-element ( san -- n ) {
+ unsigned san = T0_POP();
+ size_t u;
+
+ for (u = 0; u < CTX->num_name_elts; u ++) {
+ if (CTX->name_elts[u].status == 0) {
+ const unsigned char *oid;
+ size_t len, off;
+
+ oid = CTX->name_elts[u].oid;
+ if (san) {
+ if (oid[0] != 0 || oid[1] != 0) {
+ continue;
+ }
+ off = 2;
+ } else {
+ off = 0;
+ }
+ len = oid[off];
+ if (len != 0 && len == CTX->pad[0]
+ && memcmp(oid + off + 1,
+ CTX->pad + 1, len) == 0)
+ {
+ T0_PUSH(u);
+ T0_RET();
+ }
+ }
+ }
+ T0_PUSHi(-1);
+}
+
+cc: copy-name-element ( bool offbuf -- ) {
+ size_t len;
+ int32_t off = T0_POPi();
+ int ok = T0_POPi();
+
+ if (off >= 0) {
+ br_name_element *ne = &CTX->name_elts[off];
+
+ if (ok) {
+ len = CTX->pad[0];
+ if (len < ne->len) {
+ memcpy(ne->buf, CTX->pad + 1, len);
+ ne->buf[len] = 0;
+ ne->status = 1;
+ } else {
+ ne->status = -1;
+ }
+ } else {
+ ne->status = -1;
+ }
+ }
+}
+
+cc: copy-name-SAN ( bool tag -- ) {
+ unsigned tag = T0_POP();
+ unsigned ok = T0_POP();
+ size_t u, len;
+
+ len = CTX->pad[0];
+ for (u = 0; u < CTX->num_name_elts; u ++) {
+ br_name_element *ne;
+
+ ne = &CTX->name_elts[u];
+ if (ne->status == 0 && ne->oid[0] == 0 && ne->oid[1] == tag) {
+ if (ok && ne->len > len) {
+ memcpy(ne->buf, CTX->pad + 1, len);
+ ne->buf[len] = 0;
+ ne->status = 1;
+ } else {
+ ne->status = -1;
+ }
+ break;
+ }
+ }
+}
+
+\ Read a value, decoding string types. If the string type is recognised
+\ and the value could be converted to UTF-8 into the pad, then true (-1)
+\ is returned; in all other cases, false (0) is returned. Either way, the
+\ object is consumed.
+: read-string ( lim -- lim bool )
+ read-tag case
+ \ UTF8String
+ 12 of check-primitive read-value-UTF8 endof
+ \ NumericString
+ 18 of check-primitive read-value-latin1 endof
+ \ PrintableString
+ 19 of check-primitive read-value-latin1 endof
+ \ TeletexString
+ 20 of check-primitive read-value-latin1 endof
+ \ IA5String
+ 22 of check-primitive read-value-latin1 endof
+ \ BMPString
+ 30 of check-primitive read-value-UTF16 endof
+ 2drop read-length-skip 0 0
+ endcase ;
+
+\ Read a DN for the EE. The normalized DN hash is computed and stored in the
+\ current_dn_hash.
+\ Name elements are gathered. Also, the Common Name is matched against the
+\ intended server name.
+\ Returned value is true (-1) if the CN matches the intended server name,
+\ false (0) otherwise.
+: read-DN-EE ( lim -- lim bool )
+ \ Flag will be set to true if there is a CN and it matches the
+ \ intended server name.
+ 0 { eename-matches }
+
+ \ Activate DN hashing.
+ start-dn-hash
+
+ \ Parse the DN structure: it is a SEQUENCE of SET of
+ \ AttributeTypeAndValue. Each AttributeTypeAndValue is a
+ \ SEQUENCE { OBJECT IDENTIFIER, ANY }.
+ read-sequence-open
+ begin
+ dup while
+
+ read-tag 0x11 check-tag-constructed read-length-open-elt
+ dup ifnot ERR_X509_BAD_DN fail then
+ begin
+ dup while
+
+ read-sequence-open
+
+ \ Read the OID. If the OID could not be read (too
+ \ long) then the first pad byte will be 0.
+ read-OID drop
+
+ \ If it is the Common Name then we'll need to
+ \ match it against the intended server name (if
+ \ applicable).
+ id-at-commonName eqOID { isCN }
+
+ \ Get offset for reception buffer for that element
+ \ (or -1).
+ 0 offset-name-element { offbuf }
+
+ \ Try to read the value as a string.
+ read-string
+
+ \ If the value could be decoded as a string,
+ \ copy it and/or match it, as appropriate.
+ dup isCN and if
+ match-server-name if
+ -1 >eename-matches
+ then
+ then
+ offbuf copy-name-element
+
+ \ Close the SEQUENCE
+ close-elt
+
+ repeat
+ close-elt
+ repeat
+ close-elt
+
+ \ Compute DN hash and deactivate DN hashing.
+ compute-dn-hash
+
+ \ Return the CN match flag.
+ eename-matches ;
+
+\ Get the validation date and time from the context or system.
+cc: get-system-date ( -- days seconds ) {
+ if (CTX->days == 0 && CTX->seconds == 0) {
+#if BR_USE_UNIX_TIME
+ time_t x = time(NULL);
+
+ T0_PUSH((uint32_t)(x / 86400) + 719528);
+ T0_PUSH((uint32_t)(x % 86400));
+#elif BR_USE_WIN32_TIME
+ FILETIME ft;
+ uint64_t x;
+
+ GetSystemTimeAsFileTime(&ft);
+ x = ((uint64_t)ft.dwHighDateTime << 32)
+ + (uint64_t)ft.dwLowDateTime;
+ x = (x / 10000000);
+ T0_PUSH((uint32_t)(x / 86400) + 584754);
+ T0_PUSH((uint32_t)(x % 86400));
+#else
+ CTX->err = BR_ERR_X509_TIME_UNKNOWN;
+ T0_CO();
+#endif
+ } else {
+ T0_PUSH(CTX->days);
+ T0_PUSH(CTX->seconds);
+ }
+}
+
+\ Compare two dates (days+seconds) together.
+: before ( days1 seconds1 days2 seconds2 -- bool )
+ { d1 s1 d2 s2 }
+ d1 d2 = if s1 s2 < else d1 d2 < then ;
+
+: after ( days1 seconds1 days2 seconds2 -- bool )
+ swap2 before ;
+
+\ Swap the top two elements with the two elements immediately below.
+: swap2 ( a b c d -- c d a b )
+ 3 roll 3 roll ;
+
+\ Match the name in the pad with the expected server name. Returned value
+\ is true (-1) on match, false (0) otherwise. If there is no expected
+\ server name, then 0 is returned.
+\ Match conditions: either an exact match (case insensitive), or a
+\ wildcard match, if the found name starts with "*.". We only match a
+\ starting wildcard, and only against a complete DN name component.
+cc: match-server-name ( -- bool ) {
+ size_t n1, n2;
+
+ if (CTX->server_name == NULL) {
+ T0_PUSH(0);
+ T0_RET();
+ }
+ n1 = strlen(CTX->server_name);
+ n2 = CTX->pad[0];
+ if (n1 == n2 && eqnocase(&CTX->pad[1], CTX->server_name, n1)) {
+ T0_PUSHi(-1);
+ T0_RET();
+ }
+ if (n2 >= 2 && CTX->pad[1] == '*' && CTX->pad[2] == '.') {
+ size_t u;
+
+ u = 0;
+ while (u < n1 && CTX->server_name[u] != '.') {
+ u ++;
+ }
+ u ++;
+ n1 -= u;
+ if ((n2 - 2) == n1
+ && eqnocase(&CTX->pad[3], CTX->server_name + u, n1))
+ {
+ T0_PUSHi(-1);
+ T0_RET();
+ }
+ }
+ T0_PUSH(0);
+}
+
+\ Get the address and length for the pkey_data buffer.
+: addr-len-pkey_data ( -- addr len )
+ CX 0 8191 { offsetof(br_x509_minimal_context, pkey_data) }
+ CX 0 8191 { BR_X509_BUFSIZE_KEY } ;
+
+\ Copy the EE public key to the permanent buffer (RSA).
+cc: copy-ee-rsa-pkey ( nlen elen -- ) {
+ size_t elen = T0_POP();
+ size_t nlen = T0_POP();
+ memcpy(CTX->ee_pkey_data, CTX->pkey_data, nlen + elen);
+ CTX->pkey.key_type = BR_KEYTYPE_RSA;
+ CTX->pkey.key.rsa.n = CTX->ee_pkey_data;
+ CTX->pkey.key.rsa.nlen = nlen;
+ CTX->pkey.key.rsa.e = CTX->ee_pkey_data + nlen;
+ CTX->pkey.key.rsa.elen = elen;
+}
+
+\ Copy the EE public key to the permanent buffer (EC).
+cc: copy-ee-ec-pkey ( curve qlen -- ) {
+ size_t qlen = T0_POP();
+ uint32_t curve = T0_POP();
+ memcpy(CTX->ee_pkey_data, CTX->pkey_data, qlen);
+ CTX->pkey.key_type = BR_KEYTYPE_EC;
+ CTX->pkey.key.ec.curve = curve;
+ CTX->pkey.key.ec.q = CTX->ee_pkey_data;
+ CTX->pkey.key.ec.qlen = qlen;
+}
+
+\ Check whether the current certificate (EE) is directly trusted.
+cc: check-direct-trust ( -- ) {
+ size_t u;
+
+ for (u = 0; u < CTX->trust_anchors_num; u ++) {
+ const br_x509_trust_anchor *ta;
+ unsigned char hashed_DN[64];
+ int kt;
+
+ ta = &CTX->trust_anchors[u];
+ if (ta->flags & BR_X509_TA_CA) {
+ continue;
+ }
+ hash_dn(CTX, ta->dn.data, ta->dn.len, hashed_DN);
+ if (memcmp(hashed_DN, CTX->current_dn_hash, DNHASH_LEN)) {
+ continue;
+ }
+ kt = CTX->pkey.key_type;
+ if ((ta->pkey.key_type & 0x0F) != kt) {
+ continue;
+ }
+ switch (kt) {
+
+ case BR_KEYTYPE_RSA:
+ if (!eqbigint(CTX->pkey.key.rsa.n,
+ CTX->pkey.key.rsa.nlen,
+ ta->pkey.key.rsa.n,
+ ta->pkey.key.rsa.nlen)
+ || !eqbigint(CTX->pkey.key.rsa.e,
+ CTX->pkey.key.rsa.elen,
+ ta->pkey.key.rsa.e,
+ ta->pkey.key.rsa.elen))
+ {
+ continue;
+ }
+ break;
+
+ case BR_KEYTYPE_EC:
+ if (CTX->pkey.key.ec.curve != ta->pkey.key.ec.curve
+ || CTX->pkey.key.ec.qlen != ta->pkey.key.ec.qlen
+ || memcmp(CTX->pkey.key.ec.q,
+ ta->pkey.key.ec.q,
+ ta->pkey.key.ec.qlen) != 0)
+ {
+ continue;
+ }
+ break;
+
+ default:
+ continue;
+ }
+
+ /*
+ * Direct trust match!
+ */
+ CTX->err = BR_ERR_X509_OK;
+ T0_CO();
+ }
+}
+
+\ Check the signature on the certificate with regards to all trusted CA.
+\ We use the issuer hash (in saved_dn_hash[]) as CA identifier.
+cc: check-trust-anchor-CA ( -- ) {
+ size_t u;
+
+ for (u = 0; u < CTX->trust_anchors_num; u ++) {
+ const br_x509_trust_anchor *ta;
+ unsigned char hashed_DN[64];
+
+ ta = &CTX->trust_anchors[u];
+ if (!(ta->flags & BR_X509_TA_CA)) {
+ continue;
+ }
+ hash_dn(CTX, ta->dn.data, ta->dn.len, hashed_DN);
+ if (memcmp(hashed_DN, CTX->saved_dn_hash, DNHASH_LEN)) {
+ continue;
+ }
+ if (verify_signature(CTX, &ta->pkey) == 0) {
+ CTX->err = BR_ERR_X509_OK;
+ T0_CO();
+ }
+ }
+}
+
+\ Verify RSA signature. This uses the public key that was just decoded
+\ into CTX->pkey_data; the modulus and exponent length are provided as
+\ parameters. The resulting hash value is compared with the one in
+\ tbs_hash. Returned value is 0 on success, or a non-zero error code.
+cc: do-rsa-vrfy ( nlen elen -- err ) {
+ size_t elen = T0_POP();
+ size_t nlen = T0_POP();
+ br_x509_pkey pk;
+
+ pk.key_type = BR_KEYTYPE_RSA;
+ pk.key.rsa.n = CTX->pkey_data;
+ pk.key.rsa.nlen = nlen;
+ pk.key.rsa.e = CTX->pkey_data + nlen;
+ pk.key.rsa.elen = elen;
+ T0_PUSH(verify_signature(CTX, &pk));
+}
+
+\ Verify ECDSA signature. This uses the public key that was just decoded
+\ into CTX->pkey_dayta; the curve ID and public point length are provided
+\ as parameters. The hash value in tbs_hash is used. Returned value is 0
+\ on success, or non-zero error code.
+cc: do-ecdsa-vrfy ( curve qlen -- err ) {
+ size_t qlen = T0_POP();
+ int curve = T0_POP();
+ br_x509_pkey pk;
+
+ pk.key_type = BR_KEYTYPE_EC;
+ pk.key.ec.curve = curve;
+ pk.key.ec.q = CTX->pkey_data;
+ pk.key.ec.qlen = qlen;
+ T0_PUSH(verify_signature(CTX, &pk));
+}
+
+cc: print-bytes ( addr len -- ) {
+ extern int printf(const char *fmt, ...);
+ size_t len = T0_POP();
+ unsigned char *buf = (unsigned char *)CTX + T0_POP();
+ size_t u;
+
+ for (u = 0; u < len; u ++) {
+ printf("%02X", buf[u]);
+ }
+}
+
+cc: printOID ( -- ) {
+ extern int printf(const char *fmt, ...);
+ size_t u, len;
+
+ len = CTX->pad[0];
+ if (len == 0) {
+ printf("*");
+ T0_RET();
+ }
+ printf("%u.%u", CTX->pad[1] / 40, CTX->pad[1] % 40);
+ u = 2;
+ while (u <= len) {
+ unsigned long ul;
+
+ ul = 0;
+ for (;;) {
+ int x;
+
+ if (u > len) {
+ printf("BAD");
+ T0_RET();
+ }
+ x = CTX->pad[u ++];
+ ul = (ul << 7) + (x & 0x7F);
+ if (!(x & 0x80)) {
+ break;
+ }
+ }
+ printf(".%lu", ul);
+ }
+}
+
+\ Extensions with specific processing.
+OID: basicConstraints 2.5.29.19
+OID: keyUsage 2.5.29.15
+OID: subjectAltName 2.5.29.17
+OID: certificatePolicies 2.5.29.32
+
+\ Policy qualifier "pointer to CPS"
+OID: id-qt-cps 1.3.6.1.5.5.7.2.1
+
+\ Extensions which are ignored when encountered, even if critical.
+OID: authorityKeyIdentifier 2.5.29.35
+OID: subjectKeyIdentifier 2.5.29.14
+OID: issuerAltName 2.5.29.18
+OID: subjectDirectoryAttributes 2.5.29.9
+OID: crlDistributionPoints 2.5.29.31
+OID: freshestCRL 2.5.29.46
+OID: authorityInfoAccess 1.3.6.1.5.5.7.1.1
+OID: subjectInfoAccess 1.3.6.1.5.5.7.1.11
+
+\ Process a Basic Constraints extension. This should be called only if
+\ the certificate is not the EE. We check that the extension contains
+\ the "CA" flag, and that the path length, if specified, is compatible
+\ with the current chain length.
+: process-basicConstraints ( lim -- lim )
+ read-sequence-open
+ read-tag-or-end
+ dup 0x01 = if
+ read-boolean ifnot ERR_X509_NOT_CA fail then
+ read-tag-or-end
+ else
+ ERR_X509_NOT_CA fail
+ then
+ dup 0x02 = if
+ drop check-primitive read-small-int-value
+ addr-num_certs get32 1- < if ERR_X509_NOT_CA fail then
+ read-tag-or-end
+ then
+ -1 <> if ERR_X509_UNEXPECTED fail then
+ drop
+ close-elt
+ ;
+
+\ Process a Key Usage extension.
+\ For the EE certificate:
+\ -- if the key usage contains keyEncipherment (2), dataEncipherment (3)
+\ or keyAgreement (4), then the "key exchange" usage is allowed;
+\ -- if the key usage contains digitalSignature (0) or nonRepudiation (1),
+\ then the "signature" usage is allowed.
+\ For CA certificates, the extension must contain keyCertSign (5).
+: process-keyUsage ( lim ee -- lim )
+ { ee }
+
+ \ Read tag for the BIT STRING and open it.
+ read-tag 0x03 check-tag-primitive
+ read-length-open-elt
+ \ First byte indicates number of ignored bits in the last byte. It
+ \ must be between 0 and 7.
+ read8 { ign }
+ ign 7 > if ERR_X509_UNEXPECTED fail then
+ \ Depending on length, we have either 0, 1 or more bytes to read.
+ dup case
+ 0 of ERR_X509_FORBIDDEN_KEY_USAGE fail endof
+ 1 of read8 ign >> ign << endof
+ drop read8 0
+ endcase
+
+ \ Check bits.
+ ee if
+ \ EE: get usages.
+ 0
+ over 0x38 and if 0x10 or then
+ swap 0xC0 and if 0x20 or then
+ addr-key_usages set8
+ else
+ \ Not EE: keyCertSign must be set.
+ 0x04 and ifnot ERR_X509_FORBIDDEN_KEY_USAGE fail then
+ then
+
+ \ We don't care about subsequent bytes.
+ skip-close-elt ;
+
+\ Process a Certificate Policies extension.
+\
+\ Since we don't actually support full policies processing, this function
+\ only checks that the extension contents can be safely ignored. Indeed,
+\ we don't validate against a specific set of policies (in RFC 5280
+\ terminology, user-initial-policy-set only contains the special value
+\ any-policy). Moreover, we don't support policy constraints (if a
+\ critical Policy Constraints extension is encountered, the validation
+\ will fail). Therefore, we can safely ignore the contents of this
+\ extension, except if it is critical AND one of the policy OID has a
+\ qualifier which is distinct from id-qt-cps (because id-qt-cps is
+\ specially designated by RFC 5280 has having no mandated action).
+\
+\ This function is called only if the extension is critical.
+: process-certPolicies ( lim -- lim )
+ \ Extension value is a SEQUENCE OF PolicyInformation.
+ read-sequence-open
+ begin dup while
+ \ PolicyInformation ::= SEQUENCE {
+ \ policyIdentifier OBJECT IDENTIFIER,
+ \ policyQualifiers SEQUENCE OF PolicyQualifierInfo OPTIONAL
+ \ }
+ read-sequence-open
+ read-OID drop
+ dup if
+ read-sequence-open
+ begin dup while
+ \ PolicyQualifierInfo ::= SEQUENCE {
+ \ policyQualifierId OBJECT IDENTIFIER,
+ \ qualifier ANY
+ \ }
+ read-sequence-open
+ read-OID drop id-qt-cps eqOID ifnot
+ ERR_X509_CRITICAL_EXTENSION fail
+ then
+ skip-close-elt
+ repeat
+ close-elt
+ then
+ close-elt
+ repeat
+ close-elt ;
+
+\ Process a Subject Alt Name extension. Returned value is a boolean set
+\ to true if the expected server name was matched against a dNSName in
+\ the extension.
+: process-SAN ( lim -- lim bool )
+ 0 { m }
+ read-sequence-open
+ begin dup while
+ \ Read the tag. If the tag is context-0, then parse an
+ \ 'otherName'. If the tag is context-2, then parse a
+ \ dNSName. If the tag is context-1 or context-6,
+ \ parse
+ read-tag case
+ \ OtherName
+ 0x20 of
+ \ OtherName ::= SEQUENCE {
+ \ type-id OBJECT IDENTIFIER,
+ \ value [0] EXPLICIT ANY
+ \ }
+ check-constructed read-length-open-elt
+ read-OID drop
+ -1 offset-name-element { offbuf }
+ read-tag 0x20 check-tag-constructed
+ read-length-open-elt
+ read-string offbuf copy-name-element
+ close-elt
+ close-elt
+ endof
+ \ rfc822Name (IA5String)
+ 0x21 of
+ check-primitive
+ read-value-UTF8 1 copy-name-SAN
+ endof
+ \ dNSName (IA5String)
+ 0x22 of
+ check-primitive
+ read-value-UTF8
+ dup if match-server-name m or >m then
+ 2 copy-name-SAN
+ endof
+ \ uniformResourceIdentifier (IA5String)
+ 0x26 of
+ check-primitive
+ read-value-UTF8 6 copy-name-SAN
+ endof
+ 2drop read-length-skip 0
+ endcase
+
+ \ We check only names of type dNSName; they use IA5String,
+ \ which is basically ASCII.
+ \ read-tag 0x22 = if
+ \ check-primitive
+ \ read-small-value drop
+ \ match-server-name m or >m
+ \ else
+ \ drop read-length-skip
+ \ then
+ repeat
+ close-elt
+ m ;
+
+\ Decode a certificate. The "ee" boolean must be true for the EE.
+: decode-certificate ( ee -- )
+ { ee }
+
+ \ Obtain the total certificate length.
+ addr-cert_length get32
+
+ \ Open the outer SEQUENCE.
+ read-sequence-open
+
+ \ TBS
+ \ Activate hashing.
+ start-tbs-hash
+ read-sequence-open
+
+ \ First element may be an explicit version. We accept only
+ \ versions 0 to 2 (certificates v1 to v3).
+ read-tag dup 0x20 = if
+ drop check-constructed read-length-open-elt
+ read-tag
+ 0x02 check-tag-primitive
+ read-small-int-value
+ 2 > if ERR_X509_UNSUPPORTED fail then
+ close-elt
+ read-tag
+ then
+
+ \ Serial number. We just check that the tag is correct.
+ 0x02 check-tag-primitive
+ read-length-skip
+
+ \ Signature algorithm. This structure is redundant with the one
+ \ on the outside; we just skip it.
+ read-sequence-open skip-close-elt
+
+ \ Issuer name: hashed, then copied into next_dn_hash[].
+ read-DN
+ addr-next_dn_hash addr-current_dn_hash dn-hash-length blobcopy
+
+ \ Validity dates.
+ read-sequence-open
+ read-date get-system-date after if ERR_X509_EXPIRED fail then
+ read-date get-system-date before if ERR_X509_EXPIRED fail then
+ close-elt
+
+ \ Subject name.
+ ee if
+ \ For the EE, we must check whether the Common Name, if
+ \ any, matches the expected server name.
+ read-DN-EE { eename }
+ else
+ \ For a non-EE certificate, the hashed subject DN must match
+ \ the saved hashed issuer DN from the previous certificate.
+ read-DN
+ addr-current_dn_hash addr-saved_dn_hash dn-hash-length eqblob
+ ifnot ERR_X509_DN_MISMATCH fail then
+ then
+ \ Move the hashed issuer DN for this certificate into the
+ \ saved_dn_hash[] array.
+ addr-saved_dn_hash addr-next_dn_hash dn-hash-length blobcopy
+
+ \ Public Key.
+ read-sequence-open
+ \ Algorithm Identifier. Right now we are only interested in the
+ \ OID, since we only support RSA keys.
+ read-sequence-open
+ read-OID ifnot ERR_X509_UNSUPPORTED fail then
+ { ; pkey-type }
+ choice
+ \ RSA public key.
+ rsaEncryption eqOID uf
+ skip-close-elt
+ \ Public key itself: the BIT STRING contains bytes
+ \ (no partial byte) and these bytes encode the
+ \ actual value.
+ read-bits-open
+ \ RSA public key is a SEQUENCE of two
+ \ INTEGER. We get both INTEGER values into
+ \ the pkey_data[] buffer, if they fit.
+ read-sequence-open
+ addr-len-pkey_data
+ read-integer { nlen }
+ addr-len-pkey_data swap nlen + swap nlen -
+ read-integer { elen }
+ close-elt
+
+ \ Check that the public key fits our minimal
+ \ size requirements. Note that the integer
+ \ decoder already skipped the leading bytes
+ \ of value 0, so we are working on the true
+ \ modulus length here.
+ addr-min_rsa_size get16 128 + nlen > if
+ ERR_X509_WEAK_PUBLIC_KEY fail
+ then
+ close-elt
+ KEYTYPE_RSA >pkey-type
+ enduf
+
+ \ EC public key.
+ id-ecPublicKey eqOID uf
+ \ We support only named curves, for which the
+ \ "parameters" field in the AlgorithmIdentifier
+ \ field should be an OID.
+ read-OID ifnot ERR_X509_UNSUPPORTED fail then
+ choice
+ ansix9p256r1 eqOID uf 23 enduf
+ ansix9p384r1 eqOID uf 24 enduf
+ ansix9p521r1 eqOID uf 25 enduf
+ ERR_X509_UNSUPPORTED fail
+ endchoice
+ { curve }
+ close-elt
+ read-bits-open
+ dup { qlen }
+ dup addr-len-pkey_data rot < if
+ ERR_X509_LIMIT_EXCEEDED fail
+ then
+ read-blob
+ KEYTYPE_EC >pkey-type
+ enduf
+
+ \ Not a recognised public key type.
+ ERR_X509_UNSUPPORTED fail
+ endchoice
+ close-elt
+
+ \ Process public key.
+ ee if
+ \ For the EE certificate, copy the key data to the
+ \ relevant buffer.
+ pkey-type case
+ KEYTYPE_RSA of nlen elen copy-ee-rsa-pkey endof
+ KEYTYPE_EC of curve qlen copy-ee-ec-pkey endof
+ ERR_X509_UNSUPPORTED fail
+ endcase
+ else
+ \ Verify signature on previous certificate. We invoke
+ \ the RSA implementation.
+ pkey-type case
+ KEYTYPE_RSA of nlen elen do-rsa-vrfy endof
+ KEYTYPE_EC of curve qlen do-ecdsa-vrfy endof
+ ERR_X509_UNSUPPORTED fail
+ endcase
+ dup if fail then
+ drop
+ then
+
+ \ This flag will be set to true if the Basic Constraints extension
+ \ is encountered.
+ 0 { seenBC }
+
+ \ Skip issuerUniqueID and subjectUniqueID, and process extensions
+ \ if present. Extensions are an explicit context tag of value 3
+ \ around a SEQUENCE OF extensions. Each extension is a SEQUENCE
+ \ with an OID, an optional boolean, and a value; the value is
+ \ an OCTET STRING.
+ read-tag-or-end
+ 0x21 iftag-skip
+ 0x22 iftag-skip
+ dup 0x23 = if
+ drop
+ check-constructed read-length-open-elt
+ read-sequence-open
+ begin dup while
+ 0 { critical }
+ read-sequence-open
+ read-OID drop
+ read-tag dup 0x01 = if
+ read-boolean >critical
+ read-tag
+ then
+ 0x04 check-tag-primitive read-length-open-elt
+ choice
+ \ Extensions with specific processing.
+ basicConstraints eqOID uf
+ ee if
+ skip-remaining
+ else
+ process-basicConstraints
+ -1 >seenBC
+ then
+ enduf
+ keyUsage eqOID uf
+ ee process-keyUsage
+ enduf
+ subjectAltName eqOID uf
+ ee if
+ 0 >eename
+ process-SAN >eename
+ else
+ skip-remaining
+ then
+ enduf
+
+ \ We don't implement full processing of
+ \ policies. The call below mostly checks
+ \ that the contents of the Certificate
+ \ Policies extension can be safely ignored.
+ certificatePolicies eqOID uf
+ critical if
+ process-certPolicies
+ else
+ skip-remaining
+ then
+ enduf
+
+ \ Extensions which are always ignored,
+ \ even if critical.
+ authorityKeyIdentifier eqOID uf
+ skip-remaining
+ enduf
+ subjectKeyIdentifier eqOID uf
+ skip-remaining
+ enduf
+ issuerAltName eqOID uf
+ skip-remaining
+ enduf
+ subjectDirectoryAttributes eqOID uf
+ skip-remaining
+ enduf
+ crlDistributionPoints eqOID uf
+ skip-remaining
+ enduf
+ freshestCRL eqOID uf
+ skip-remaining
+ enduf
+ authorityInfoAccess eqOID uf
+ skip-remaining
+ enduf
+ subjectInfoAccess eqOID uf
+ skip-remaining
+ enduf
+
+ \ Unrecognized extensions trigger a failure
+ \ if critical; otherwise, they are just
+ \ ignored.
+ critical if
+ ERR_X509_CRITICAL_EXTENSION fail
+ then
+ skip-remaining
+ endchoice
+ close-elt
+ close-elt
+ repeat
+ close-elt
+ close-elt
+ else
+ -1 = ifnot ERR_X509_UNEXPECTED fail then
+ drop
+ then
+
+ close-elt
+ \ Terminate hashing.
+ stop-tbs-hash
+
+ \ For the EE certificate, verify that the intended server name
+ \ was matched.
+ ee if
+ eename zero-server-name or ifnot
+ ERR_X509_BAD_SERVER_NAME fail
+ then
+ then
+
+ \ If this is the EE certificate, then direct trust may apply.
+ \ Note: we do this at this point, not immediately after decoding
+ \ the public key, because even in case of direct trust we still
+ \ want to check the server name with regards to the SAN extension.
+ \ However, we want to check direct trust before trying to decode
+ \ the signature algorithm, because it should work even if that
+ \ algorithm is not supported.
+ ee if check-direct-trust then
+
+ \ Non-EE certificates MUST have a Basic Constraints extension
+ \ (that marks them as being CA).
+ ee seenBC or ifnot ERR_X509_NOT_CA fail then
+
+ \ signature algorithm
+ read-tag check-sequence read-length-open-elt
+ \ Read and understand the OID. Right now, we support only
+ \ RSA with PKCS#1 v1.5 padding, and hash functions SHA-1,
+ \ SHA-224, SHA-256, SHA-384 and SHA-512. We purposely do NOT
+ \ support MD5 here.
+ \ TODO: add support for RSA/PSS
+ read-OID if
+ \ Based on the signature OID, we get:
+ \ -- the signing key type
+ \ -- the hash function numeric identifier
+ \ -- the hash function OID
+ choice
+ sha1WithRSAEncryption eqOID
+ uf 2 KEYTYPE_RSA id-sha1 enduf
+ sha224WithRSAEncryption eqOID
+ uf 3 KEYTYPE_RSA id-sha224 enduf
+ sha256WithRSAEncryption eqOID
+ uf 4 KEYTYPE_RSA id-sha256 enduf
+ sha384WithRSAEncryption eqOID
+ uf 5 KEYTYPE_RSA id-sha384 enduf
+ sha512WithRSAEncryption eqOID
+ uf 6 KEYTYPE_RSA id-sha512 enduf
+
+ ecdsa-with-SHA1 eqOID
+ uf 2 KEYTYPE_EC id-sha1 enduf
+ ecdsa-with-SHA224 eqOID
+ uf 3 KEYTYPE_EC id-sha224 enduf
+ ecdsa-with-SHA256 eqOID
+ uf 4 KEYTYPE_EC id-sha256 enduf
+ ecdsa-with-SHA384 eqOID
+ uf 5 KEYTYPE_EC id-sha384 enduf
+ ecdsa-with-SHA512 eqOID
+ uf 6 KEYTYPE_EC id-sha512 enduf
+ ERR_X509_UNSUPPORTED fail
+ endchoice
+ addr-cert_sig_hash_oid set16
+ addr-cert_signer_key_type set8
+
+ \ Compute the TBS hash into tbs_hash.
+ compute-tbs-hash
+ dup ifnot ERR_X509_UNSUPPORTED fail then
+ addr-cert_sig_hash_len set8
+ else
+ ERR_X509_UNSUPPORTED fail
+ then
+ \ We ignore the parameters, whether they are present or not,
+ \ because we got all the information from the OID.
+ skip-close-elt
+
+ \ signature value
+ read-bits-open
+ dup CX 0 8191 { BR_X509_BUFSIZE_SIG } > if
+ ERR_X509_LIMIT_EXCEEDED fail
+ then
+ dup addr-cert_sig_len set16
+ addr-cert_sig read-blob
+
+ \ Close the outer SEQUENCE.
+ close-elt
+
+ \ Close the advertised total certificate length. This checks that
+ \ there is no trailing garbage after the certificate.
+ close-elt
+
+ \ Flag the certificate as fully processed.
+ 0 addr-cert_length set32
+
+ \ Check whether the issuer for the current certificate is known
+ \ as a trusted CA; in which case, verify the signature.
+ check-trust-anchor-CA ;
+
+: main
+ \ Unless restricted by a Key Usage extension, all usages are
+ \ deemed allowed.
+ 0x30 addr-key_usages set8
+ -1 decode-certificate
+ co
+ begin
+ 0 decode-certificate co
+ again
+ ;
diff --git a/test/monniaux/BearSSL/src/x509/x509_minimal_full.c b/test/monniaux/BearSSL/src/x509/x509_minimal_full.c
new file mode 100644
index 00000000..2b544267
--- /dev/null
+++ b/test/monniaux/BearSSL/src/x509/x509_minimal_full.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_x509.h */
+void
+br_x509_minimal_init_full(br_x509_minimal_context *xc,
+ const br_x509_trust_anchor *trust_anchors, size_t trust_anchors_num)
+{
+ /*
+ * All hash functions are activated.
+ * Note: the X.509 validation engine will nonetheless refuse to
+ * validate signatures that use MD5 as hash function.
+ */
+ static const br_hash_class *hashes[] = {
+ &br_md5_vtable,
+ &br_sha1_vtable,
+ &br_sha224_vtable,
+ &br_sha256_vtable,
+ &br_sha384_vtable,
+ &br_sha512_vtable
+ };
+
+ int id;
+
+ br_x509_minimal_init(xc, &br_sha256_vtable,
+ trust_anchors, trust_anchors_num);
+ br_x509_minimal_set_rsa(xc, &br_rsa_i31_pkcs1_vrfy);
+ br_x509_minimal_set_ecdsa(xc,
+ &br_ec_prime_i31, &br_ecdsa_i31_vrfy_asn1);
+ for (id = br_md5_ID; id <= br_sha512_ID; id ++) {
+ const br_hash_class *hc;
+
+ hc = hashes[id - 1];
+ br_x509_minimal_set_hash(xc, id, hc);
+ }
+}