--- /dev/null
+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.
--- /dev/null
+# 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.
+
+.POSIX:
+
+# ========================================================================
+# Configurable elements: C compiler and flags, linker flags, static
+# library archival command.
+
+CC = gcc
+CFLAGS = -W -Wall -Os -fPIC -I src -I inc
+#CFLAGS = -W -Wall -g -fPIC -I src -I inc
+LDFLAGS =
+AR = ar -rcs
+
+# Nothing is meant to be changed below this line.
+
+# ========================================================================
+
+HEADERS = inc/bearssl.h inc/bearssl_block.h inc/bearssl_ec.h inc/bearssl_hash.h inc/bearssl_hmac.h inc/bearssl_pem.h inc/bearssl_prf.h inc/bearssl_rand.h inc/bearssl_rsa.h inc/bearssl_ssl.h inc/bearssl_x509.h src/inner.h src/config.h
+BUILD = build
+
+BEARSSLLIB = libbearssl.a
+BRSSL = brssl
+TESTCRYPTO = testcrypto
+TESTSPEED = testspeed
+TESTX509 = testx509
+TESTMATH = testmath
+
+OBJCODEC = $(BUILD)/ccopy.o $(BUILD)/dec16be.o $(BUILD)/dec16le.o $(BUILD)/dec32be.o $(BUILD)/dec32le.o $(BUILD)/dec64be.o $(BUILD)/dec64le.o $(BUILD)/enc16be.o $(BUILD)/enc16le.o $(BUILD)/enc32be.o $(BUILD)/enc32le.o $(BUILD)/enc64be.o $(BUILD)/enc64le.o $(BUILD)/pemdec.o
+OBJEC = $(BUILD)/ec_prime_i31.o $(BUILD)/ec_prime_i31_secp256r1.o $(BUILD)/ec_prime_i31_secp384r1.o $(BUILD)/ec_prime_i31_secp521r1.o $(BUILD)/ec_secp256r1.o $(BUILD)/ec_secp384r1.o $(BUILD)/ec_secp521r1.o $(BUILD)/ecdsa_atr.o $(BUILD)/ecdsa_i31_bits.o $(BUILD)/ecdsa_i31_sign_asn1.o $(BUILD)/ecdsa_i31_sign_raw.o $(BUILD)/ecdsa_i31_vrfy_asn1.o $(BUILD)/ecdsa_i31_vrfy_raw.o $(BUILD)/ecdsa_rta.o
+OBJHASH = $(BUILD)/dig_oid.o $(BUILD)/dig_size.o $(BUILD)/ghash_ctmul.o $(BUILD)/ghash_ctmul32.o $(BUILD)/ghash_ctmul64.o $(BUILD)/md5.o $(BUILD)/md5sha1.o $(BUILD)/multihash.o $(BUILD)/sha1.o $(BUILD)/sha2big.o $(BUILD)/sha2small.o
+OBJINT31 = $(BUILD)/i31_add.o $(BUILD)/i31_bitlen.o $(BUILD)/i31_decmod.o $(BUILD)/i31_decode.o $(BUILD)/i31_decred.o $(BUILD)/i31_encode.o $(BUILD)/i31_fmont.o $(BUILD)/i31_iszero.o $(BUILD)/i31_modpow.o $(BUILD)/i31_montmul.o $(BUILD)/i31_mulacc.o $(BUILD)/i31_muladd.o $(BUILD)/i31_ninv31.o $(BUILD)/i31_reduce.o $(BUILD)/i31_rshift.o $(BUILD)/i31_sub.o $(BUILD)/i31_tmont.o
+OBJINT32 = $(BUILD)/i32_add.o $(BUILD)/i32_bitlen.o $(BUILD)/i32_decmod.o $(BUILD)/i32_decode.o $(BUILD)/i32_decred.o $(BUILD)/i32_div32.o $(BUILD)/i32_encode.o $(BUILD)/i32_fmont.o $(BUILD)/i32_iszero.o $(BUILD)/i32_modpow.o $(BUILD)/i32_montmul.o $(BUILD)/i32_mulacc.o $(BUILD)/i32_muladd.o $(BUILD)/i32_ninv32.o $(BUILD)/i32_reduce.o $(BUILD)/i32_sub.o $(BUILD)/i32_tmont.o
+OBJMAC = $(BUILD)/hmac.o $(BUILD)/hmac_ct.o
+OBJRAND = $(BUILD)/hmac_drbg.o
+OBJRSA = $(BUILD)/rsa_i31_pkcs1_sign.o $(BUILD)/rsa_i31_pkcs1_vrfy.o $(BUILD)/rsa_i31_priv.o $(BUILD)/rsa_i31_pub.o $(BUILD)/rsa_i32_pkcs1_sign.o $(BUILD)/rsa_i32_pkcs1_vrfy.o $(BUILD)/rsa_i32_priv.o $(BUILD)/rsa_i32_pub.o $(BUILD)/rsa_ssl_decrypt.o
+OBJSSL = $(BUILD)/prf.o $(BUILD)/prf_md5sha1.o $(BUILD)/prf_sha256.o $(BUILD)/prf_sha384.o $(BUILD)/ssl_client.o $(BUILD)/ssl_client_full.o $(BUILD)/ssl_engine.o $(BUILD)/ssl_hashes.o $(BUILD)/ssl_hs_client.o $(BUILD)/ssl_hs_server.o $(BUILD)/ssl_io.o $(BUILD)/ssl_lru.o $(BUILD)/ssl_rec_cbc.o $(BUILD)/ssl_rec_gcm.o $(BUILD)/ssl_server.o $(BUILD)/ssl_server_mine2g.o $(BUILD)/ssl_server_minf2g.o $(BUILD)/ssl_server_minr2g.o $(BUILD)/ssl_server_minu2g.o $(BUILD)/ssl_server_minv2g.o $(BUILD)/ssl_server_full_ec.o $(BUILD)/ssl_server_full_rsa.o $(BUILD)/ssl_single_ec.o $(BUILD)/ssl_single_rsa.o
+OBJSYMCIPHER = $(BUILD)/aes_big_cbcdec.o $(BUILD)/aes_big_cbcenc.o $(BUILD)/aes_big_ctr.o $(BUILD)/aes_big_dec.o $(BUILD)/aes_big_enc.o $(BUILD)/aes_common.o $(BUILD)/aes_ct.o $(BUILD)/aes_ct64.o $(BUILD)/aes_ct64_cbcdec.o $(BUILD)/aes_ct64_cbcenc.o $(BUILD)/aes_ct64_ctr.o $(BUILD)/aes_ct64_dec.o $(BUILD)/aes_ct64_enc.o $(BUILD)/aes_ct_cbcdec.o $(BUILD)/aes_ct_cbcenc.o $(BUILD)/aes_ct_ctr.o $(BUILD)/aes_ct_dec.o $(BUILD)/aes_ct_enc.o $(BUILD)/aes_small_cbcdec.o $(BUILD)/aes_small_cbcenc.o $(BUILD)/aes_small_ctr.o $(BUILD)/aes_small_dec.o $(BUILD)/aes_small_enc.o $(BUILD)/des_ct.o $(BUILD)/des_ct_cbcdec.o $(BUILD)/des_ct_cbcenc.o $(BUILD)/des_support.o $(BUILD)/des_tab.o $(BUILD)/des_tab_cbcdec.o $(BUILD)/des_tab_cbcenc.o
+OBJX509 = $(BUILD)/skey_decoder.o $(BUILD)/x509_decoder.o $(BUILD)/x509_knownkey.o $(BUILD)/x509_minimal.o
+OBJ = $(OBJCODEC) $(OBJEC) $(OBJHASH) $(OBJINT31) $(OBJINT32) $(OBJMAC) $(OBJRAND) $(OBJRSA) $(OBJSSL) $(OBJSYMCIPHER) $(OBJX509)
+OBJBRSSL = $(BUILD)/brssl.o $(BUILD)/certs.o $(BUILD)/chain.o $(BUILD)/client.o $(BUILD)/errors.o $(BUILD)/files.o $(BUILD)/keys.o $(BUILD)/names.o $(BUILD)/server.o $(BUILD)/skey.o $(BUILD)/sslio.o $(BUILD)/ta.o $(BUILD)/vector.o $(BUILD)/verify.o $(BUILD)/xmem.o
+OBJTESTCRYPTO = $(BUILD)/test_crypto.o
+OBJTESTSPEED = $(BUILD)/test_speed.o
+OBJTESTX509 = $(BUILD)/test_x509.o
+OBJTESTMATH = $(BUILD)/test_math.o
+
+T0COMP = T0Comp.exe
+T0SRC = T0/BlobWriter.cs T0/CPU.cs T0/CodeElement.cs T0/CodeElementJump.cs T0/CodeElementUInt.cs T0/CodeElementUIntExpr.cs T0/CodeElementUIntInt.cs T0/CodeElementUIntUInt.cs T0/ConstData.cs T0/Opcode.cs T0/OpcodeCall.cs T0/OpcodeConst.cs T0/OpcodeGetLocal.cs T0/OpcodeJump.cs T0/OpcodeJumpIf.cs T0/OpcodeJumpIfNot.cs T0/OpcodeJumpUncond.cs T0/OpcodePutLocal.cs T0/OpcodeRet.cs T0/SType.cs T0/T0Comp.cs T0/TPointerBase.cs T0/TPointerBlob.cs T0/TPointerExpr.cs T0/TPointerNull.cs T0/TPointerXT.cs T0/TValue.cs T0/Word.cs T0/WordBuilder.cs T0/WordData.cs T0/WordInterpreted.cs T0/WordNative.cs
+T0KERN = T0/kern.t0
+
+all: compile
+
+compile: $(BEARSSLLIB) $(BRSSL) $(TESTCRYPTO) $(TESTSPEED) $(TESTX509)
+
+$(BEARSSLLIB): $(BUILD) $(OBJ)
+ $(AR) $(BEARSSLLIB) $(OBJ)
+
+$(BRSSL): $(BEARSSLLIB) $(OBJBRSSL)
+ $(CC) $(LDFLAGS) -o $(BRSSL) $(OBJBRSSL) $(BEARSSLLIB)
+
+$(TESTCRYPTO): $(BEARSSLLIB) $(OBJTESTCRYPTO)
+ $(CC) $(LDFLAGS) -o $(TESTCRYPTO) $(OBJTESTCRYPTO) $(BEARSSLLIB)
+
+$(TESTSPEED): $(BEARSSLLIB) $(OBJTESTSPEED)
+ $(CC) $(LDFLAGS) -o $(TESTSPEED) $(OBJTESTSPEED) $(BEARSSLLIB)
+
+$(TESTX509): $(BEARSSLLIB) $(OBJTESTX509)
+ $(CC) $(LDFLAGS) -o $(TESTX509) $(OBJTESTX509) $(BEARSSLLIB)
+
+$(TESTMATH): $(BEARSSLLIB) $(OBJTESTMATH)
+ $(CC) $(LDFLAGS) -o $(TESTMATH) $(OBJTESTMATH) $(BEARSSLLIB) -lgmp
+
+$(BUILD):
+ -mkdir -p $(BUILD)
+
+T0: $(T0COMP) T0Gen
+
+T0Gen:
+ mono T0Comp.exe -o src/codec/pemdec -r br_pem_decoder src/codec/pemdec.t0
+ mono T0Comp.exe -o src/ssl/ssl_hs_client -r br_ssl_hs_client src/ssl/ssl_hs_common.t0 src/ssl/ssl_hs_client.t0
+ mono T0Comp.exe -o src/ssl/ssl_hs_server -r br_ssl_hs_server src/ssl/ssl_hs_common.t0 src/ssl/ssl_hs_server.t0
+ mono T0Comp.exe -o src/x509/skey_decoder -r br_skey_decoder src/x509/asn1.t0 src/x509/skey_decoder.t0
+ mono T0Comp.exe -o src/x509/x509_decoder -r br_x509_decoder src/x509/asn1.t0 src/x509/x509_decoder.t0
+ mono T0Comp.exe -o src/x509/x509_minimal -r br_x509_minimal src/x509/asn1.t0 src/x509/x509_minimal.t0
+
+$(T0COMP): $(T0SRC) $(T0KERN)
+ ./mkT0.sh
+
+clean:
+ -rm -f $(OBJ) $(BEARSSLLIB) $(OBJSSL) $(BRSSL) $(OBJBRSSL) $(TESTCRYPTO) $(OBJTESTCRYPTO) $(TESTSPEED) $(OBJTESTSPEED) $(TESTX509) $(OBJTESTX509) $(TESTMATH) $(OBJTESTMATH)
+
+$(BUILD)/ccopy.o: src/codec/ccopy.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/ccopy.o src/codec/ccopy.c
+
+$(BUILD)/dec16be.o: src/codec/dec16be.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/dec16be.o src/codec/dec16be.c
+
+$(BUILD)/dec16le.o: src/codec/dec16le.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/dec16le.o src/codec/dec16le.c
+
+$(BUILD)/dec32be.o: src/codec/dec32be.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/dec32be.o src/codec/dec32be.c
+
+$(BUILD)/dec32le.o: src/codec/dec32le.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/dec32le.o src/codec/dec32le.c
+
+$(BUILD)/dec64be.o: src/codec/dec64be.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/dec64be.o src/codec/dec64be.c
+
+$(BUILD)/dec64le.o: src/codec/dec64le.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/dec64le.o src/codec/dec64le.c
+
+$(BUILD)/enc16be.o: src/codec/enc16be.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/enc16be.o src/codec/enc16be.c
+
+$(BUILD)/enc16le.o: src/codec/enc16le.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/enc16le.o src/codec/enc16le.c
+
+$(BUILD)/enc32be.o: src/codec/enc32be.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/enc32be.o src/codec/enc32be.c
+
+$(BUILD)/enc32le.o: src/codec/enc32le.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/enc32le.o src/codec/enc32le.c
+
+$(BUILD)/enc64be.o: src/codec/enc64be.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/enc64be.o src/codec/enc64be.c
+
+$(BUILD)/enc64le.o: src/codec/enc64le.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/enc64le.o src/codec/enc64le.c
+
+$(BUILD)/pemdec.o: src/codec/pemdec.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/pemdec.o src/codec/pemdec.c
+
+$(BUILD)/ec_g_secp256r1.o: src/ec/ec_g_secp256r1.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/ec_g_secp256r1.o src/ec/ec_g_secp256r1.c
+
+$(BUILD)/ec_g_secp384r1.o: src/ec/ec_g_secp384r1.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/ec_g_secp384r1.o src/ec/ec_g_secp384r1.c
+
+$(BUILD)/ec_g_secp521r1.o: src/ec/ec_g_secp521r1.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/ec_g_secp521r1.o src/ec/ec_g_secp521r1.c
+
+
+$(BUILD)/ec_prime_i31.o: src/ec/ec_prime_i31.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/ec_prime_i31.o src/ec/ec_prime_i31.c
+
+$(BUILD)/ec_prime_i31_secp256r1.o: src/ec/ec_prime_i31_secp256r1.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/ec_prime_i31_secp256r1.o src/ec/ec_prime_i31_secp256r1.c
+
+$(BUILD)/ec_prime_i31_secp384r1.o: src/ec/ec_prime_i31_secp384r1.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/ec_prime_i31_secp384r1.o src/ec/ec_prime_i31_secp384r1.c
+
+$(BUILD)/ec_prime_i31_secp521r1.o: src/ec/ec_prime_i31_secp521r1.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/ec_prime_i31_secp521r1.o src/ec/ec_prime_i31_secp521r1.c
+
+$(BUILD)/ec_secp256r1.o: src/ec/ec_secp256r1.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/ec_secp256r1.o src/ec/ec_secp256r1.c
+
+$(BUILD)/ec_secp384r1.o: src/ec/ec_secp384r1.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/ec_secp384r1.o src/ec/ec_secp384r1.c
+
+$(BUILD)/ec_secp521r1.o: src/ec/ec_secp521r1.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/ec_secp521r1.o src/ec/ec_secp521r1.c
+
+$(BUILD)/ecdsa_atr.o: src/ec/ecdsa_atr.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/ecdsa_atr.o src/ec/ecdsa_atr.c
+
+$(BUILD)/ecdsa_i31_bits.o: src/ec/ecdsa_i31_bits.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/ecdsa_i31_bits.o src/ec/ecdsa_i31_bits.c
+
+$(BUILD)/ecdsa_i31_sign_asn1.o: src/ec/ecdsa_i31_sign_asn1.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/ecdsa_i31_sign_asn1.o src/ec/ecdsa_i31_sign_asn1.c
+
+$(BUILD)/ecdsa_i31_sign_raw.o: src/ec/ecdsa_i31_sign_raw.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/ecdsa_i31_sign_raw.o src/ec/ecdsa_i31_sign_raw.c
+
+$(BUILD)/ecdsa_i31_vrfy_asn1.o: src/ec/ecdsa_i31_vrfy_asn1.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/ecdsa_i31_vrfy_asn1.o src/ec/ecdsa_i31_vrfy_asn1.c
+
+$(BUILD)/ecdsa_i31_vrfy_raw.o: src/ec/ecdsa_i31_vrfy_raw.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/ecdsa_i31_vrfy_raw.o src/ec/ecdsa_i31_vrfy_raw.c
+
+$(BUILD)/ecdsa_rta.o: src/ec/ecdsa_rta.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/ecdsa_rta.o src/ec/ecdsa_rta.c
+
+$(BUILD)/dig_oid.o: src/hash/dig_oid.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/dig_oid.o src/hash/dig_oid.c
+
+$(BUILD)/dig_size.o: src/hash/dig_size.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/dig_size.o src/hash/dig_size.c
+
+$(BUILD)/ghash_ctmul.o: src/hash/ghash_ctmul.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/ghash_ctmul.o src/hash/ghash_ctmul.c
+
+$(BUILD)/ghash_ctmul32.o: src/hash/ghash_ctmul32.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/ghash_ctmul32.o src/hash/ghash_ctmul32.c
+
+$(BUILD)/ghash_ctmul64.o: src/hash/ghash_ctmul64.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/ghash_ctmul64.o src/hash/ghash_ctmul64.c
+
+$(BUILD)/md5.o: src/hash/md5.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/md5.o src/hash/md5.c
+
+$(BUILD)/md5sha1.o: src/hash/md5sha1.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/md5sha1.o src/hash/md5sha1.c
+
+$(BUILD)/multihash.o: src/hash/multihash.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/multihash.o src/hash/multihash.c
+
+$(BUILD)/sha1.o: src/hash/sha1.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/sha1.o src/hash/sha1.c
+
+$(BUILD)/sha2big.o: src/hash/sha2big.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/sha2big.o src/hash/sha2big.c
+
+$(BUILD)/sha2small.o: src/hash/sha2small.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/sha2small.o src/hash/sha2small.c
+
+$(BUILD)/i31_add.o: src/int/i31_add.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/i31_add.o src/int/i31_add.c
+
+$(BUILD)/i31_bitlen.o: src/int/i31_bitlen.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/i31_bitlen.o src/int/i31_bitlen.c
+
+$(BUILD)/i31_decmod.o: src/int/i31_decmod.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/i31_decmod.o src/int/i31_decmod.c
+
+$(BUILD)/i31_decode.o: src/int/i31_decode.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/i31_decode.o src/int/i31_decode.c
+
+$(BUILD)/i31_decred.o: src/int/i31_decred.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/i31_decred.o src/int/i31_decred.c
+
+$(BUILD)/i31_encode.o: src/int/i31_encode.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/i31_encode.o src/int/i31_encode.c
+
+$(BUILD)/i31_fmont.o: src/int/i31_fmont.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/i31_fmont.o src/int/i31_fmont.c
+
+$(BUILD)/i31_iszero.o: src/int/i31_iszero.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/i31_iszero.o src/int/i31_iszero.c
+
+$(BUILD)/i31_modpow.o: src/int/i31_modpow.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/i31_modpow.o src/int/i31_modpow.c
+
+$(BUILD)/i31_montmul.o: src/int/i31_montmul.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/i31_montmul.o src/int/i31_montmul.c
+
+$(BUILD)/i31_mulacc.o: src/int/i31_mulacc.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/i31_mulacc.o src/int/i31_mulacc.c
+
+$(BUILD)/i31_muladd.o: src/int/i31_muladd.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/i31_muladd.o src/int/i31_muladd.c
+
+$(BUILD)/i31_ninv31.o: src/int/i31_ninv31.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/i31_ninv31.o src/int/i31_ninv31.c
+
+$(BUILD)/i31_reduce.o: src/int/i31_reduce.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/i31_reduce.o src/int/i31_reduce.c
+
+$(BUILD)/i31_rshift.o: src/int/i31_rshift.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/i31_rshift.o src/int/i31_rshift.c
+
+$(BUILD)/i31_sub.o: src/int/i31_sub.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/i31_sub.o src/int/i31_sub.c
+
+$(BUILD)/i31_tmont.o: src/int/i31_tmont.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/i31_tmont.o src/int/i31_tmont.c
+
+$(BUILD)/i32_add.o: src/int/i32_add.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/i32_add.o src/int/i32_add.c
+
+$(BUILD)/i32_bitlen.o: src/int/i32_bitlen.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/i32_bitlen.o src/int/i32_bitlen.c
+
+$(BUILD)/i32_decmod.o: src/int/i32_decmod.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/i32_decmod.o src/int/i32_decmod.c
+
+$(BUILD)/i32_decode.o: src/int/i32_decode.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/i32_decode.o src/int/i32_decode.c
+
+$(BUILD)/i32_decred.o: src/int/i32_decred.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/i32_decred.o src/int/i32_decred.c
+
+$(BUILD)/i32_div32.o: src/int/i32_div32.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/i32_div32.o src/int/i32_div32.c
+
+$(BUILD)/i32_encode.o: src/int/i32_encode.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/i32_encode.o src/int/i32_encode.c
+
+$(BUILD)/i32_fmont.o: src/int/i32_fmont.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/i32_fmont.o src/int/i32_fmont.c
+
+$(BUILD)/i32_iszero.o: src/int/i32_iszero.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/i32_iszero.o src/int/i32_iszero.c
+
+$(BUILD)/i32_modpow.o: src/int/i32_modpow.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/i32_modpow.o src/int/i32_modpow.c
+
+$(BUILD)/i32_montmul.o: src/int/i32_montmul.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/i32_montmul.o src/int/i32_montmul.c
+
+$(BUILD)/i32_mulacc.o: src/int/i32_mulacc.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/i32_mulacc.o src/int/i32_mulacc.c
+
+$(BUILD)/i32_muladd.o: src/int/i32_muladd.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/i32_muladd.o src/int/i32_muladd.c
+
+$(BUILD)/i32_ninv32.o: src/int/i32_ninv32.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/i32_ninv32.o src/int/i32_ninv32.c
+
+$(BUILD)/i32_reduce.o: src/int/i32_reduce.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/i32_reduce.o src/int/i32_reduce.c
+
+$(BUILD)/i32_sub.o: src/int/i32_sub.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/i32_sub.o src/int/i32_sub.c
+
+$(BUILD)/i32_tmont.o: src/int/i32_tmont.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/i32_tmont.o src/int/i32_tmont.c
+
+$(BUILD)/hmac.o: src/mac/hmac.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/hmac.o src/mac/hmac.c
+
+$(BUILD)/hmac_ct.o: src/mac/hmac_ct.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/hmac_ct.o src/mac/hmac_ct.c
+
+$(BUILD)/hmac_drbg.o: src/rand/hmac_drbg.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/hmac_drbg.o src/rand/hmac_drbg.c
+
+$(BUILD)/rsa_i31_pkcs1_sign.o: src/rsa/rsa_i31_pkcs1_sign.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/rsa_i31_pkcs1_sign.o src/rsa/rsa_i31_pkcs1_sign.c
+
+$(BUILD)/rsa_i31_pkcs1_vrfy.o: src/rsa/rsa_i31_pkcs1_vrfy.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/rsa_i31_pkcs1_vrfy.o src/rsa/rsa_i31_pkcs1_vrfy.c
+
+$(BUILD)/rsa_i31_priv.o: src/rsa/rsa_i31_priv.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/rsa_i31_priv.o src/rsa/rsa_i31_priv.c
+
+$(BUILD)/rsa_i31_pub.o: src/rsa/rsa_i31_pub.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/rsa_i31_pub.o src/rsa/rsa_i31_pub.c
+
+$(BUILD)/rsa_i32_pkcs1_sign.o: src/rsa/rsa_i32_pkcs1_sign.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/rsa_i32_pkcs1_sign.o src/rsa/rsa_i32_pkcs1_sign.c
+
+$(BUILD)/rsa_i32_pkcs1_vrfy.o: src/rsa/rsa_i32_pkcs1_vrfy.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/rsa_i32_pkcs1_vrfy.o src/rsa/rsa_i32_pkcs1_vrfy.c
+
+$(BUILD)/rsa_i32_priv.o: src/rsa/rsa_i32_priv.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/rsa_i32_priv.o src/rsa/rsa_i32_priv.c
+
+$(BUILD)/rsa_i32_pub.o: src/rsa/rsa_i32_pub.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/rsa_i32_pub.o src/rsa/rsa_i32_pub.c
+
+$(BUILD)/rsa_ssl_decrypt.o: src/rsa/rsa_ssl_decrypt.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/rsa_ssl_decrypt.o src/rsa/rsa_ssl_decrypt.c
+
+$(BUILD)/prf.o: src/ssl/prf.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/prf.o src/ssl/prf.c
+
+$(BUILD)/prf_md5sha1.o: src/ssl/prf_md5sha1.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/prf_md5sha1.o src/ssl/prf_md5sha1.c
+
+$(BUILD)/prf_sha256.o: src/ssl/prf_sha256.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/prf_sha256.o src/ssl/prf_sha256.c
+
+$(BUILD)/prf_sha384.o: src/ssl/prf_sha384.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/prf_sha384.o src/ssl/prf_sha384.c
+
+$(BUILD)/ssl_client.o: src/ssl/ssl_client.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/ssl_client.o src/ssl/ssl_client.c
+
+$(BUILD)/ssl_client_full.o: src/ssl/ssl_client_full.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/ssl_client_full.o src/ssl/ssl_client_full.c
+
+$(BUILD)/ssl_engine.o: src/ssl/ssl_engine.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/ssl_engine.o src/ssl/ssl_engine.c
+
+$(BUILD)/ssl_hashes.o: src/ssl/ssl_hashes.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/ssl_hashes.o src/ssl/ssl_hashes.c
+
+$(BUILD)/ssl_hs_client.o: src/ssl/ssl_hs_client.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/ssl_hs_client.o src/ssl/ssl_hs_client.c
+
+$(BUILD)/ssl_hs_server.o: src/ssl/ssl_hs_server.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/ssl_hs_server.o src/ssl/ssl_hs_server.c
+
+$(BUILD)/ssl_io.o: src/ssl/ssl_io.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/ssl_io.o src/ssl/ssl_io.c
+
+$(BUILD)/ssl_lru.o: src/ssl/ssl_lru.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/ssl_lru.o src/ssl/ssl_lru.c
+
+$(BUILD)/ssl_rec_cbc.o: src/ssl/ssl_rec_cbc.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/ssl_rec_cbc.o src/ssl/ssl_rec_cbc.c
+
+$(BUILD)/ssl_rec_gcm.o: src/ssl/ssl_rec_gcm.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/ssl_rec_gcm.o src/ssl/ssl_rec_gcm.c
+
+$(BUILD)/ssl_server.o: src/ssl/ssl_server.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/ssl_server.o src/ssl/ssl_server.c
+
+$(BUILD)/ssl_server_mine2g.o: src/ssl/ssl_server_mine2g.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/ssl_server_mine2g.o src/ssl/ssl_server_mine2g.c
+
+$(BUILD)/ssl_server_minf2g.o: src/ssl/ssl_server_minf2g.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/ssl_server_minf2g.o src/ssl/ssl_server_minf2g.c
+
+$(BUILD)/ssl_server_minr2g.o: src/ssl/ssl_server_minr2g.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/ssl_server_minr2g.o src/ssl/ssl_server_minr2g.c
+
+$(BUILD)/ssl_server_minu2g.o: src/ssl/ssl_server_minu2g.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/ssl_server_minu2g.o src/ssl/ssl_server_minu2g.c
+
+$(BUILD)/ssl_server_minv2g.o: src/ssl/ssl_server_minv2g.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/ssl_server_minv2g.o src/ssl/ssl_server_minv2g.c
+
+$(BUILD)/ssl_server_full_ec.o: src/ssl/ssl_server_full_ec.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/ssl_server_full_ec.o src/ssl/ssl_server_full_ec.c
+
+$(BUILD)/ssl_server_full_rsa.o: src/ssl/ssl_server_full_rsa.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/ssl_server_full_rsa.o src/ssl/ssl_server_full_rsa.c
+
+$(BUILD)/ssl_single_ec.o: src/ssl/ssl_single_ec.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/ssl_single_ec.o src/ssl/ssl_single_ec.c
+
+$(BUILD)/ssl_single_rsa.o: src/ssl/ssl_single_rsa.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/ssl_single_rsa.o src/ssl/ssl_single_rsa.c
+
+$(BUILD)/aes_big_cbcdec.o: src/symcipher/aes_big_cbcdec.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/aes_big_cbcdec.o src/symcipher/aes_big_cbcdec.c
+
+$(BUILD)/aes_big_cbcenc.o: src/symcipher/aes_big_cbcenc.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/aes_big_cbcenc.o src/symcipher/aes_big_cbcenc.c
+
+$(BUILD)/aes_big_ctr.o: src/symcipher/aes_big_ctr.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/aes_big_ctr.o src/symcipher/aes_big_ctr.c
+
+$(BUILD)/aes_big_dec.o: src/symcipher/aes_big_dec.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/aes_big_dec.o src/symcipher/aes_big_dec.c
+
+$(BUILD)/aes_big_enc.o: src/symcipher/aes_big_enc.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/aes_big_enc.o src/symcipher/aes_big_enc.c
+
+$(BUILD)/aes_common.o: src/symcipher/aes_common.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/aes_common.o src/symcipher/aes_common.c
+
+$(BUILD)/aes_ct.o: src/symcipher/aes_ct.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/aes_ct.o src/symcipher/aes_ct.c
+
+$(BUILD)/aes_ct64.o: src/symcipher/aes_ct64.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/aes_ct64.o src/symcipher/aes_ct64.c
+
+$(BUILD)/aes_ct64_cbcdec.o: src/symcipher/aes_ct64_cbcdec.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/aes_ct64_cbcdec.o src/symcipher/aes_ct64_cbcdec.c
+
+$(BUILD)/aes_ct64_cbcenc.o: src/symcipher/aes_ct64_cbcenc.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/aes_ct64_cbcenc.o src/symcipher/aes_ct64_cbcenc.c
+
+$(BUILD)/aes_ct64_ctr.o: src/symcipher/aes_ct64_ctr.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/aes_ct64_ctr.o src/symcipher/aes_ct64_ctr.c
+
+$(BUILD)/aes_ct64_dec.o: src/symcipher/aes_ct64_dec.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/aes_ct64_dec.o src/symcipher/aes_ct64_dec.c
+
+$(BUILD)/aes_ct64_enc.o: src/symcipher/aes_ct64_enc.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/aes_ct64_enc.o src/symcipher/aes_ct64_enc.c
+
+$(BUILD)/aes_ct_cbcdec.o: src/symcipher/aes_ct_cbcdec.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/aes_ct_cbcdec.o src/symcipher/aes_ct_cbcdec.c
+
+$(BUILD)/aes_ct_cbcenc.o: src/symcipher/aes_ct_cbcenc.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/aes_ct_cbcenc.o src/symcipher/aes_ct_cbcenc.c
+
+$(BUILD)/aes_ct_ctr.o: src/symcipher/aes_ct_ctr.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/aes_ct_ctr.o src/symcipher/aes_ct_ctr.c
+
+$(BUILD)/aes_ct_dec.o: src/symcipher/aes_ct_dec.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/aes_ct_dec.o src/symcipher/aes_ct_dec.c
+
+$(BUILD)/aes_ct_enc.o: src/symcipher/aes_ct_enc.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/aes_ct_enc.o src/symcipher/aes_ct_enc.c
+
+$(BUILD)/aes_small_cbcdec.o: src/symcipher/aes_small_cbcdec.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/aes_small_cbcdec.o src/symcipher/aes_small_cbcdec.c
+
+$(BUILD)/aes_small_cbcenc.o: src/symcipher/aes_small_cbcenc.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/aes_small_cbcenc.o src/symcipher/aes_small_cbcenc.c
+
+$(BUILD)/aes_small_ctr.o: src/symcipher/aes_small_ctr.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/aes_small_ctr.o src/symcipher/aes_small_ctr.c
+
+$(BUILD)/aes_small_dec.o: src/symcipher/aes_small_dec.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/aes_small_dec.o src/symcipher/aes_small_dec.c
+
+$(BUILD)/aes_small_enc.o: src/symcipher/aes_small_enc.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/aes_small_enc.o src/symcipher/aes_small_enc.c
+
+$(BUILD)/des_ct.o: src/symcipher/des_ct.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/des_ct.o src/symcipher/des_ct.c
+
+$(BUILD)/des_ct_cbcdec.o: src/symcipher/des_ct_cbcdec.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/des_ct_cbcdec.o src/symcipher/des_ct_cbcdec.c
+
+$(BUILD)/des_ct_cbcenc.o: src/symcipher/des_ct_cbcenc.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/des_ct_cbcenc.o src/symcipher/des_ct_cbcenc.c
+
+$(BUILD)/des_support.o: src/symcipher/des_support.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/des_support.o src/symcipher/des_support.c
+
+$(BUILD)/des_tab.o: src/symcipher/des_tab.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/des_tab.o src/symcipher/des_tab.c
+
+$(BUILD)/des_tab_cbcdec.o: src/symcipher/des_tab_cbcdec.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/des_tab_cbcdec.o src/symcipher/des_tab_cbcdec.c
+
+$(BUILD)/des_tab_cbcenc.o: src/symcipher/des_tab_cbcenc.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/des_tab_cbcenc.o src/symcipher/des_tab_cbcenc.c
+
+$(BUILD)/skey_decoder.o: src/x509/skey_decoder.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/skey_decoder.o src/x509/skey_decoder.c
+
+$(BUILD)/x509_decoder.o: src/x509/x509_decoder.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/x509_decoder.o src/x509/x509_decoder.c
+
+$(BUILD)/x509_knownkey.o: src/x509/x509_knownkey.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/x509_knownkey.o src/x509/x509_knownkey.c
+
+$(BUILD)/x509_minimal.o: src/x509/x509_minimal.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/x509_minimal.o src/x509/x509_minimal.c
+
+$(BUILD)/test_crypto.o: test/test_crypto.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/test_crypto.o test/test_crypto.c
+
+$(BUILD)/test_math.o: test/test_math.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/test_math.o test/test_math.c
+
+$(BUILD)/test_speed.o: test/test_speed.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/test_speed.o test/test_speed.c
+
+$(BUILD)/test_x509.o: test/test_x509.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/test_x509.o test/test_x509.c
+
+$(BUILD)/brssl.o: tools/brssl.c tools/brssl.h $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/brssl.o tools/brssl.c
+
+$(BUILD)/certs.o: tools/certs.c tools/brssl.h $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/certs.o tools/certs.c
+
+$(BUILD)/chain.o: tools/chain.c tools/brssl.h $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/chain.o tools/chain.c
+
+$(BUILD)/client.o: tools/client.c tools/brssl.h $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/client.o tools/client.c
+
+$(BUILD)/errors.o: tools/errors.c tools/brssl.h $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/errors.o tools/errors.c
+
+$(BUILD)/files.o: tools/files.c tools/brssl.h $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/files.o tools/files.c
+
+$(BUILD)/keys.o: tools/keys.c tools/brssl.h $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/keys.o tools/keys.c
+
+$(BUILD)/names.o: tools/names.c tools/brssl.h $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/names.o tools/names.c
+
+$(BUILD)/server.o: tools/server.c tools/brssl.h $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/server.o tools/server.c
+
+$(BUILD)/skey.o: tools/skey.c tools/brssl.h $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/skey.o tools/skey.c
+
+$(BUILD)/sslio.o: tools/sslio.c tools/brssl.h $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/sslio.o tools/sslio.c
+
+$(BUILD)/ta.o: tools/ta.c tools/brssl.h $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/ta.o tools/ta.c
+
+$(BUILD)/vector.o: tools/vector.c tools/brssl.h $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/vector.o tools/vector.c
+
+$(BUILD)/verify.o: tools/verify.c tools/brssl.h $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/verify.o tools/verify.c
+
+$(BUILD)/xmem.o: tools/xmem.c tools/brssl.h $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $(BUILD)/xmem.o tools/xmem.c
--- /dev/null
+# Disclaimer
+
+BearSSL is for now considered alpha-level software. This means that it
+probably still has some bugs, possibly very serious ones (e.g. buffer
+overflows -- one of the perks of using C as programming language). It
+still lacks some functionalities. The API will probably change and may
+break both source and binary compatibility.
+
+In other words, you would be quite mad to use it for any production
+purpose. Right now, this is for learning, testing and possibly
+contributing.
+
+The usage license is explicited in the `LICENSE.txt` file. This is the
+"MIT license". It can be summarised in the following way:
+
+ - You can use and reuse the library as you wish, and modify it, and
+ integrate it in your own code, and distribute it as is or in any
+ modified form, and so on.
+
+ - The only obligation that the license terms put upon you is that you
+ acknowledge and make it clear that if anything breaks, it is not my
+ fault, and I am not liable for anything, regardless of the type and
+ amount of collateral damage. The license terms say that the copyright
+ notice "shall be included in all copies or substantial portions of
+ the Software": this is how the disclaimer is "made explicit".
+ Basically, I have put it in every source file, so just keep it there.
+
+# Installation
+
+As of version 0.1, BearSSL is a simple static library. Most of the
+process is rather manual and old-style, and there is no installer (this
+will be added in a later version, in particular when all the man pages
+for BearSSL functions are written).
+
+ 1. Have a look at the top of the `Makefile`. There you can configure the
+ command names and flags for invoking the C compiler, linker, and
+ static library archiver.
+
+ 2. There are a few configurable switches in `src/config.h`. These switches
+ relate to compile-time options, e.g. support of a system-provided
+ random source. On usual platforms (e.g. Linux or OS X), auto-detection
+ should work, but you can always override things with `config.h`.
+
+ 3. Type `make`. This should produce the static library (`libbearssl.a`),
+ the test executables (`testcrypto`, `testspeed` and `testx509`), and
+ the command-line debug tool (`brssl`). You might want to run the tests:
+
+ - `testcrypto all` runs the cryptographic tests (test vectors on all
+ implemented cryptogaphic functions). It can be slow.
+
+ - `testspeed all` runs a number of performance benchmarks, there again
+ on cryptographic functions. It gives a taste of how things go on the
+ current platform.
+
+ - `testx509` runs X.509 validation tests. The test certificates are
+ all in `test/x509/`.
+
+ 4. The `brssl` command-line tool is a stand-alone binary. It can exercise
+ some of the functionalities of BearSSL, in particular running a test
+ SSL client or server. It is not meant for production purposes (e.g.
+ the SSL client has a mode where it disregards the inability to validate
+ the server's certificate, which is inherently unsafe, but convenient
+ for debug).
+
+ 5. Using the library means writing some application code that invokes it,
+ and linking with the static library. The header files are all in the
+ `inc` directory; copy them wherever makes sense (e.g. in the
+ `/usr/local/include` directory). The library itself (`libbearssl.a`)
+ is what you link against.
+
+ Alternatively, you may want to copy the source files directly into
+ your own application code. This will make integrating ulterior versions
+ of BearSSL more difficult. If you still want to go down that road,
+ then simply copy all the `*.h` and `*.c` files from the `src` and `inc`
+ directories into your application source code. In the BearSSL source
+ archive, the source files are segregated into various sub-directories,
+ but this is for my convenience only. There is no technical requirement
+ for that, and all files can be dumped together in a simple directory.
+
+ Dependencies are simple and systematic:
+
+ - Each `*.c` file includes `inner.h`
+ - `inner.h` includes `config.h` and `bearssl.h`
+ - `bearssl.h` includes the other `bearssl_*.h`
+
+# Versioning
+
+I follow this simple version numbering scheme:
+
+ - Version numbers are `x.y` or `x.y.z` where `x`, `y` ans `z` are
+ decimal integers (possibly greater than 10). When the `.z` part is
+ missing, it is equivalent to `.0`.
+
+ - Backward compatibility is maintained, at both source and binary levels,
+ for each major version: this means that if some application code was
+ designed for version `x.y`, then it should compile, link and run
+ properly with any version `x.y'` for any `y'` greater than `y`.
+
+ The major version `0` is an exception. You shall not expect that any
+ version that starts with `0.` offers any kind of compatibility,
+ either source or binary, with any other `0.` version. (Of course I
+ will try to maintain some decent level of source compatibility, but I
+ make no promise in that respect. Since the API uses caller-allocated
+ context structures, I already know that binary compatibility _will_
+ be broken.)
+
+ - Sub-versions (the `y` part) are about added functionality. That is,
+ it can be expected that `1.3` will contain some extra functions when
+ compared to `1.2`. The next version level (the `z` part) is for
+ bugfixes that do not add any functionality.
+
+# API Usage
+
+Right now there is little documentation. The following principles are
+maintained:
+
+ - All public symbols (global functions and data elements, macros) have
+ a name that starts with `br_` or `BR_`.
+
+ - The header files (the `bearssl_*.h` in the `inc` directory) contain
+ for now the most complete documentation (as comments).
+
+ - Context structures are allocated by the caller. BearSSL does not
+ contain any single `malloc()` call; this means that there is no
+ "freeing up" call to be done. When you don't need some BearSSL
+ functionality, just cease to call it, and that's it.
+
+ - BearSSL contains no modifiable static data. It is thus thread-safe
+ and reentrant, _for distinct contexts_. Accessing the same context
+ structure from distinct threads, though, is a recipe for disaster.
+
+ - The main SSL I/O API is organised as a state machine. A running
+ SSL engine (client or server) has four I/O ports:
+
+ - It can receive bytes from the transport medium ("record data").
+ - It can send bytes to the transport medium.
+ - It can receive application data, to be sent to the peer through
+ the SSL tunnel.
+ - It can produce application data, built from the records sent by
+ the peer.
+
+ BearSSL never performs I/O by itself; it expects the caller to
+ provide or retrieve the data. Each port consists in a pair of
+ functions: one yields the pointer to the buffer from which data
+ can be read or to which data can be written, and the maximum
+ size for such an operation; the other function is used to
+ inform the engine about how many bytes were actually read or
+ written.
+
+ For instance, if the `br_ssl_engine_sendrec_buf()` function returns a
+ non-NULL pointer, then this means that there are bytes to be sent to
+ the transport medium. When the caller has indeed sent some or all of
+ these bytes, it informs the engine with
+ `br_ssl_engine_sendrec_ack()`.
+
+ This state-machine API means that the engine never blocks. Each
+ invocation may trigger computations, but will always return as
+ promptly as the CPU power allows. All the I/O waiting is supposed to
+ be done on the outside. This structure allows managing several
+ concurrent SSL engines, along with other I/O tasks, with a single
+ mono-threaded loop using `select()` or `poll()`. It also makes it
+ easier to integrate BearSSL with various transport mechanisms (e.g.
+ messages in the EAP-TLS authentication framework).
+
+ - Nevertheless, there are situations where simple blocking calls _can_
+ be used, and are convenient. For these situations, use the
+ `br_sslio_context` wrapper. Then do blocking reads and writes with
+ `br_sslio_read()` and similar functions. The sample client code
+ in `samples/client_basic.c` shows how such things are done.
--- /dev/null
+/*
+ * 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.
+ */
+
+using System;
+using System.IO;
+using System.Text;
+
+/*
+ * A simple class for writing out bytes as hexadecimal constants or
+ * explicit expressions for the initializer of a C array of 'unsigned
+ * char'. It starts every line with a given number of tabs, and aims at
+ * keeping lines below a given threshold (each indentation tab counts as
+ * 8 characters). An explicit newline is inserted before the first
+ * element, and commas are used as separators.
+ */
+
+class BlobWriter {
+
+ TextWriter w;
+ int maxLineLen;
+ int indent;
+ int lineLen;
+
+ /*
+ * Create a new instance. 'maxLineLen' is in characters, and
+ * 'indent' is the number of tab characters at the start of
+ * each line.
+ */
+ internal BlobWriter(TextWriter w, int maxLineLen, int indent)
+ {
+ this.w = w;
+ this.maxLineLen = maxLineLen;
+ this.indent = indent;
+ lineLen = -1;
+ }
+
+ void DoNL()
+ {
+ w.WriteLine();
+ for (int i = 0; i < indent; i ++) {
+ w.Write('\t');
+ }
+ lineLen = (indent << 3);
+ }
+
+ /*
+ * Append a new byte value; it will be converted to an hexadecimal
+ * constant in the output.
+ */
+ internal void Append(byte b)
+ {
+ if (lineLen < 0) {
+ DoNL();
+ } else {
+ w.Write(',');
+ lineLen ++;
+ if ((lineLen + 5) > maxLineLen) {
+ DoNL();
+ } else {
+ w.Write(' ');
+ lineLen ++;
+ }
+ }
+ w.Write("0x{0:X2}", b);
+ lineLen += 4;
+ }
+
+ /*
+ * Append a C expression, which will be used as is. The expression
+ * may resolve to several bytes if it uses internal commas. The
+ * writer will try to honour the expected line length, but it
+ * won't insert a newline character inside the expression.
+ */
+ internal void Append(string expr)
+ {
+ if (lineLen < 0) {
+ DoNL();
+ } else {
+ w.Write(',');
+ lineLen ++;
+ if ((lineLen + 1 + expr.Length) > maxLineLen) {
+ DoNL();
+ } else {
+ w.Write(' ');
+ lineLen ++;
+ }
+ }
+ w.Write("{0}", expr);
+ lineLen += expr.Length;
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+using System;
+using System.Collections.Generic;
+
+/*
+ * Execution of code during compilation is done in a virtual CPU
+ * incarnated by this class, that contains the relevant registers.
+ *
+ * Accesses to the data on the stack are mapped to accesses to an
+ * internal array, with no explicit control on boundaries. Since the
+ * internal array may be larger than the actual stack contents,
+ * nonsensical accesses may still "work" to some extent. The whole
+ * thing won't derail beyond the CLR VM, though.
+ */
+
+class CPU {
+
+ /*
+ * Next instruction to execute is in ipBuf[ipOff].
+ */
+ internal Opcode[] ipBuf;
+ internal int ipOff;
+
+ /*
+ * stackBuf and stackPtr implement the data stack. The system
+ * stack uses frames; 'rsp' points to the current top frame.
+ */
+ TValue[] stackBuf;
+ int stackPtr;
+ Frame rsp;
+
+ internal CPU()
+ {
+ stackBuf = new TValue[16];
+ stackPtr = -1;
+ rsp = null;
+ }
+
+ /*
+ * Enter a function, reserving space for 'numLocals' local variables.
+ */
+ internal void Enter(Opcode[] code, int numLocals)
+ {
+ Frame f = new Frame(rsp, numLocals);
+ rsp = f;
+ f.savedIpBuf = ipBuf;
+ f.savedIpOff = ipOff;
+ ipBuf = code;
+ ipOff = 0;
+ }
+
+ /*
+ * Exit the current function.
+ */
+ internal void Exit()
+ {
+ ipBuf = rsp.savedIpBuf;
+ ipOff = rsp.savedIpOff;
+ rsp = rsp.upper;
+ }
+
+ /*
+ * Get the current stack depth (number of elements).
+ */
+ internal int Depth {
+ get {
+ return stackPtr + 1;
+ }
+ }
+
+ /*
+ * Pop a value from the stack.
+ */
+ internal TValue Pop()
+ {
+ return stackBuf[stackPtr --];
+ }
+
+ /*
+ * Push a value on the stack.
+ */
+ internal void Push(TValue v)
+ {
+ int len = stackBuf.Length;
+ if (++ stackPtr == len) {
+ TValue[] nbuf = new TValue[len << 1];
+ Array.Copy(stackBuf, 0, nbuf, 0, len);
+ stackBuf = nbuf;
+ }
+ stackBuf[stackPtr] = v;
+ }
+
+ /*
+ * Look at the value at depth 'depth' (0 is top of stack). The
+ * stack is unchanged.
+ */
+ internal TValue Peek(int depth)
+ {
+ return stackBuf[stackPtr - depth];
+ }
+
+ /*
+ * Rotate the stack at depth 'depth': the value at that depth
+ * is moved to the top of stack.
+ */
+ internal void Rot(int depth)
+ {
+ TValue v = stackBuf[stackPtr - depth];
+ Array.Copy(stackBuf, stackPtr - (depth - 1),
+ stackBuf, stackPtr - depth, depth);
+ stackBuf[stackPtr] = v;
+ }
+
+ /*
+ * Inverse-rotate the stack at depth 'depth': the value at the
+ * top of stack is moved to that depth.
+ */
+ internal void NRot(int depth)
+ {
+ TValue v = stackBuf[stackPtr];
+ Array.Copy(stackBuf, stackPtr - depth,
+ stackBuf, stackPtr - (depth - 1), depth);
+ stackBuf[stackPtr - depth] = v;
+ }
+
+ /*
+ * Get the current contents of the local variable 'num'.
+ */
+ internal TValue GetLocal(int num)
+ {
+ return rsp.locals[num];
+ }
+
+ /*
+ * Set the contents of the local variable 'num'.
+ */
+ internal void PutLocal(int num, TValue v)
+ {
+ rsp.locals[num] = v;
+ }
+
+ /*
+ * The system stack really is a linked list of Frame instances.
+ */
+ class Frame {
+
+ internal Frame upper;
+ internal Opcode[] savedIpBuf;
+ internal int savedIpOff;
+ internal TValue[] locals;
+
+ internal Frame(Frame upper, int numLocals)
+ {
+ this.upper = upper;
+ locals = new TValue[numLocals];
+ }
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+using System;
+
+abstract class CodeElement {
+
+ internal int Address { get; set; }
+
+ internal int LastLength { get; set; }
+
+ internal abstract int Length { get; }
+
+ internal CodeElement()
+ {
+ Address = -1;
+ }
+
+ internal virtual void SetJumpTarget(CodeElement target)
+ {
+ throw new Exception("Code element accepts no target");
+ }
+
+ internal abstract int Encode(BlobWriter bw);
+
+ internal static int Encode7EUnsigned(uint val, BlobWriter bw)
+ {
+ int len = 1;
+ for (uint w = val; w >= 0x80; w >>= 7) {
+ len ++;
+ }
+ if (bw != null) {
+ for (int k = (len - 1) * 7; k >= 0; k -= 7) {
+ int x = (int)(val >> k) & 0x7F;
+ if (k > 0) {
+ x |= 0x80;
+ }
+ bw.Append((byte)x);
+ }
+ }
+ return len;
+ }
+
+ internal static int Encode7ESigned(int val, BlobWriter bw)
+ {
+ int len = 1;
+ if (val < 0) {
+ for (int w = val; w < -0x40; w >>= 7) {
+ len ++;
+ }
+ } else {
+ for (int w = val; w >= 0x40; w >>= 7) {
+ len ++;
+ }
+ }
+ if (bw != null) {
+ for (int k = (len - 1) * 7; k >= 0; k -= 7) {
+ int x = (int)(val >> k) & 0x7F;
+ if (k > 0) {
+ x |= 0x80;
+ }
+ bw.Append((byte)x);
+ }
+ }
+ return len;
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+using System;
+
+class CodeElementJump : CodeElement {
+
+ uint jumpType;
+ CodeElement target;
+
+ internal CodeElementJump(uint jumpType)
+ {
+ this.jumpType = jumpType;
+ }
+
+ internal override int Length {
+ get {
+ int len = Encode7EUnsigned(jumpType, null);
+ int joff = JumpOff;
+ if (joff == Int32.MinValue) {
+ len ++;
+ } else {
+ len += Encode7ESigned(joff, null);
+ }
+ return len;
+ }
+ }
+
+ internal override void SetJumpTarget(CodeElement target)
+ {
+ this.target = target;
+ }
+
+ int JumpOff {
+ get {
+ if (target == null || Address < 0 || target.Address < 0)
+ {
+ return Int32.MinValue;
+ } else {
+ return target.Address - (Address + LastLength);
+ }
+ }
+ }
+
+ internal override int Encode(BlobWriter bw)
+ {
+ if (bw == null) {
+ return Length;
+ }
+ int len = Encode7EUnsigned(jumpType, bw);
+ int joff = JumpOff;
+ if (joff == Int32.MinValue) {
+ throw new Exception("Unresolved addresses");
+ }
+ return len + Encode7ESigned(joff, bw);
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+using System;
+
+class CodeElementUInt : CodeElement {
+
+ uint val;
+
+ internal CodeElementUInt(uint val) : base()
+ {
+ this.val = val;
+ }
+
+ internal override int Length {
+ get {
+ return Encode7EUnsigned(val, null);
+ }
+ }
+
+ internal override int Encode(BlobWriter bw)
+ {
+ return Encode7EUnsigned(val, bw);
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+using System;
+
+class CodeElementUIntExpr : CodeElement {
+
+ uint val;
+ TPointerExpr cx;
+ int off;
+
+ internal CodeElementUIntExpr(uint val,
+ TPointerExpr cx, int off) : base()
+ {
+ this.val = val;
+ this.cx = cx;
+ this.off = off;
+ }
+
+ internal override int Length {
+ get {
+ return Encode7EUnsigned(val, null)
+ + (cx.GetMaxBitLength(off) + 6) / 7;
+ }
+ }
+
+ internal override int Encode(BlobWriter bw)
+ {
+ int len1 = Encode7EUnsigned(val, bw);
+ int len2 = (cx.GetMaxBitLength(off) + 6) / 7;
+ bw.Append(String.Format("T0_INT{0}({1})",
+ len2, cx.ToCExpr(off)));
+ return len1 + len2;
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+using System;
+
+class CodeElementUIntInt : CodeElement {
+
+ uint val1;
+ int val2;
+
+ internal CodeElementUIntInt(uint val1, int val2) : base()
+ {
+ this.val1 = val1;
+ this.val2 = val2;
+ }
+
+ internal override int Length {
+ get {
+ return Encode7EUnsigned(val1, null)
+ + Encode7ESigned(val2, null);
+ }
+ }
+
+ internal override int Encode(BlobWriter bw)
+ {
+ int len = Encode7EUnsigned(val1, bw);
+ len += Encode7ESigned(val2, bw);
+ return len;
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+using System;
+
+class CodeElementUIntUInt : CodeElement {
+
+ uint val1, val2;
+
+ internal CodeElementUIntUInt(uint val1, uint val2) : base()
+ {
+ this.val1 = val1;
+ this.val2 = val2;
+ }
+
+ internal override int Length {
+ get {
+ return Encode7EUnsigned(val1, null)
+ + Encode7EUnsigned(val2, null);
+ }
+ }
+
+ internal override int Encode(BlobWriter bw)
+ {
+ int len = Encode7EUnsigned(val1, bw);
+ len += Encode7EUnsigned(val2, bw);
+ return len;
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+class ConstData {
+
+ internal long ID { get; private set; }
+ internal int Address { get; set; }
+ internal int Length {
+ get {
+ return len;
+ }
+ }
+
+ byte[] buf;
+ int len;
+
+ internal ConstData(T0Comp ctx)
+ {
+ ID = ctx.NextBlobID();
+ buf = new byte[4];
+ len = 0;
+ }
+
+ void Expand(int elen)
+ {
+ int tlen = len + elen;
+ if (tlen > buf.Length) {
+ int nlen = Math.Max(buf.Length << 1, tlen);
+ byte[] nbuf = new byte[nlen];
+ Array.Copy(buf, 0, nbuf, 0, len);
+ buf = nbuf;
+ }
+ }
+
+ internal void Add8(byte b)
+ {
+ Expand(1);
+ buf[len ++] = b;
+ }
+
+ internal void Add16(int x)
+ {
+ Expand(2);
+ buf[len ++] = (byte)(x >> 8);
+ buf[len ++] = (byte)x;
+ }
+
+ internal void Add24(int x)
+ {
+ Expand(3);
+ buf[len ++] = (byte)(x >> 16);
+ buf[len ++] = (byte)(x >> 8);
+ buf[len ++] = (byte)x;
+ }
+
+ internal void Add32(int x)
+ {
+ Expand(4);
+ buf[len ++] = (byte)(x >> 24);
+ buf[len ++] = (byte)(x >> 16);
+ buf[len ++] = (byte)(x >> 8);
+ buf[len ++] = (byte)x;
+ }
+
+ internal void AddString(string s)
+ {
+ byte[] sd = Encoding.UTF8.GetBytes(s);
+ Expand(sd.Length + 1);
+ Array.Copy(sd, 0, buf, len, sd.Length);
+ buf[len + sd.Length] = 0;
+ len += sd.Length + 1;
+ }
+
+ void CheckIndex(int off, int dlen)
+ {
+ if (off < 0 || off > (len - dlen)) {
+ throw new IndexOutOfRangeException();
+ }
+ }
+
+ internal void Set8(int off, byte v)
+ {
+ CheckIndex(off, 1);
+ buf[off] = v;
+ }
+
+ internal byte Read8(int off)
+ {
+ CheckIndex(off, 1);
+ return buf[off];
+ }
+
+ internal int Read16(int off)
+ {
+ CheckIndex(off, 2);
+ return (buf[off] << 8) | buf[off + 1];
+ }
+
+ internal int Read24(int off)
+ {
+ CheckIndex(off, 3);
+ return (buf[off] << 16) | (buf[off + 1] << 8) | buf[off + 2];
+ }
+
+ internal int Read32(int off)
+ {
+ CheckIndex(off, 4);
+ return (buf[off] << 24) | (buf[off + 1] << 16)
+ | (buf[off + 2] << 8) | buf[off + 3];
+ }
+
+ internal string ToString(int off)
+ {
+ StringBuilder sb = new StringBuilder();
+ for (;;) {
+ int x = DecodeUTF8(ref off);
+ if (x == 0) {
+ return sb.ToString();
+ }
+ if (x < 0x10000) {
+ sb.Append((char)x);
+ } else {
+ x -= 0x10000;
+ sb.Append((char)(0xD800 + (x >> 10)));
+ sb.Append((char)(0xDC00 + (x & 0x3FF)));
+ }
+ }
+ }
+
+ int DecodeUTF8(ref int off)
+ {
+ if (off >= len) {
+ throw new IndexOutOfRangeException();
+ }
+ int x = buf[off ++];
+ if (x < 0xC0 || x > 0xF7) {
+ return x;
+ }
+ int elen, acc;
+ if (x >= 0xF0) {
+ elen = 3;
+ acc = x & 0x07;
+ } else if (x >= 0xE0) {
+ elen = 2;
+ acc = x & 0x0F;
+ } else {
+ elen = 1;
+ acc = x & 0x1F;
+ }
+ if (off + elen > len) {
+ return x;
+ }
+ for (int i = 0; i < elen; i ++) {
+ int y = buf[off + i];
+ if (y < 0x80 || y >= 0xC0) {
+ return x;
+ }
+ acc = (acc << 6) + (y & 0x3F);
+ }
+ if (acc > 0x10FFFF) {
+ return x;
+ }
+ off += elen;
+ return acc;
+ }
+
+ internal void Encode(BlobWriter bw)
+ {
+ for (int i = 0; i < len; i ++) {
+ bw.Append(buf[i]);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+using System;
+using System.Collections.Generic;
+
+abstract class Opcode {
+
+ internal Opcode()
+ {
+ }
+
+ /*
+ * Execute this opcode.
+ */
+ internal abstract void Run(CPU cpu);
+
+ /*
+ * Resolve the target (word reference) for this opcode.
+ */
+ internal virtual void ResolveTarget(Word target)
+ {
+ throw new Exception("Not a call opcode");
+ }
+
+ /*
+ * Resolve the jump offset for this opcode. Displacement is
+ * relative to the address of the opcode that immediately follows
+ * the jump code; thus, 0 implies no jump at all.
+ */
+ internal virtual void ResolveJump(int disp)
+ {
+ throw new Exception("Not a jump opcode");
+ }
+
+ /*
+ * Get the Word that this opcode references; this can happen
+ * only with "call" and "const" opcodes. For all other opcodes,
+ * this method returns null.
+ */
+ internal virtual Word GetReference(T0Comp ctx)
+ {
+ return null;
+ }
+
+ /*
+ * Get the data block that this opcode references; this can happen
+ * only with "const" opcodes. For all other opcodes, this method
+ * returns null.
+ */
+ internal virtual ConstData GetDataBlock(T0Comp ctx)
+ {
+ return null;
+ }
+
+ /*
+ * Test whether this opcode may "fall through", i.e. execution
+ * may at least potentially proceed to the next opcode.
+ */
+ internal virtual bool MayFallThrough {
+ get {
+ return true;
+ }
+ }
+
+ /*
+ * Get jump displacement. For non-jump opcodes, this returns 0.
+ */
+ internal virtual int JumpDisp {
+ get {
+ return 0;
+ }
+ }
+
+ /*
+ * Get stack effect for this opcode (number of elements added to
+ * the stack, could be negative). For OpcodeCall, this returns
+ * 0.
+ */
+ internal virtual int StackAction {
+ get {
+ return 0;
+ }
+ }
+
+ internal abstract CodeElement ToCodeElement();
+
+ /*
+ * This method is called for the CodeElement corresponding to
+ * this opcode, at gcode[off]; it is used to compute actual
+ * byte jump offsets when converting code to C.
+ */
+ internal virtual void FixUp(CodeElement[] gcode, int off)
+ {
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+using System;
+using System.Collections.Generic;
+
+class OpcodeCall : Opcode {
+
+ Word target;
+
+ internal OpcodeCall() : this(null)
+ {
+ }
+
+ internal OpcodeCall(Word target)
+ {
+ this.target = target;
+ }
+
+ internal override void ResolveTarget(Word target)
+ {
+ if (this.target != null) {
+ throw new Exception("Opcode already resolved");
+ }
+ this.target = target;
+ }
+
+ internal override void Run(CPU cpu)
+ {
+ target.Run(cpu);
+ }
+
+ internal override Word GetReference(T0Comp ctx)
+ {
+ if (target == null) {
+ throw new Exception("Unresolved call target");
+ }
+ return target;
+ }
+
+ internal override CodeElement ToCodeElement()
+ {
+ return new CodeElementUInt((uint)target.Slot);
+ }
+
+ public override string ToString()
+ {
+ return "call " + (target == null ? "UNRESOLVED" : target.Name);
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+using System;
+using System.Collections.Generic;
+
+class OpcodeConst : Opcode {
+
+ TValue val;
+
+ internal OpcodeConst(TValue val)
+ {
+ this.val = val;
+ }
+
+ internal override void Run(CPU cpu)
+ {
+ cpu.Push(val);
+ }
+
+ internal override Word GetReference(T0Comp ctx)
+ {
+ TPointerXT xt = val.ptr as TPointerXT;
+ if (xt == null) {
+ return null;
+ }
+ xt.Resolve(ctx);
+ return xt.Target;
+ }
+
+ internal override ConstData GetDataBlock(T0Comp ctx)
+ {
+ TPointerBlob bp = val.ptr as TPointerBlob;
+ return bp == null ? null : bp.Blob;
+ }
+
+ internal override CodeElement ToCodeElement()
+ {
+ if (val.ptr == null) {
+ return new CodeElementUIntInt(1, val.Int);
+ }
+ TPointerXT xt = val.ptr as TPointerXT;
+ if (xt != null) {
+ if (val.x != 0) {
+ throw new Exception(
+ "Cannot compile XT: non-zero offset");
+ }
+ return new CodeElementUIntInt(1, xt.Target.Slot);
+ }
+ TPointerBlob bp = val.ptr as TPointerBlob;
+ if (bp != null) {
+ return new CodeElementUIntInt(1,
+ val.x + bp.Blob.Address);
+ }
+ TPointerExpr cx = val.ptr as TPointerExpr;
+ if (cx != null) {
+ return new CodeElementUIntExpr(1, cx, val.x);
+ }
+ throw new Exception(String.Format(
+ "Cannot embed constant (type = {0})",
+ val.ptr.GetType().FullName));
+ }
+
+ internal override int StackAction {
+ get {
+ return 1;
+ }
+ }
+
+ public override string ToString()
+ {
+ return "const " + val.ToString();
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+using System;
+using System.Collections.Generic;
+
+class OpcodeGetLocal : Opcode {
+
+ int num;
+
+ internal OpcodeGetLocal(int num)
+ {
+ this.num = num;
+ }
+
+ internal override void Run(CPU cpu)
+ {
+ cpu.Push(cpu.GetLocal(num));
+ }
+
+ internal override CodeElement ToCodeElement()
+ {
+ return new CodeElementUIntUInt(2, (uint)num);
+ }
+
+ internal override int StackAction {
+ get {
+ return 1;
+ }
+ }
+
+ public override string ToString()
+ {
+ return "getlocal " + num;
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+using System;
+using System.Collections.Generic;
+
+abstract class OpcodeJump : Opcode {
+
+ int disp;
+
+ internal OpcodeJump() : this(Int32.MinValue)
+ {
+ }
+
+ internal OpcodeJump(int disp)
+ {
+ this.disp = disp;
+ }
+
+ internal override int JumpDisp {
+ get {
+ return disp;
+ }
+ }
+
+ internal override void Run(CPU cpu)
+ {
+ cpu.ipOff += disp;
+ }
+
+ internal override void ResolveJump(int disp)
+ {
+ if (this.disp != Int32.MinValue) {
+ throw new Exception("Jump already resolved");
+ }
+ this.disp = disp;
+ }
+
+ internal override void FixUp(CodeElement[] gcode, int off)
+ {
+ gcode[off].SetJumpTarget(gcode[off + 1 + disp]);
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+using System;
+using System.Collections.Generic;
+
+class OpcodeJumpIf : OpcodeJump {
+
+ internal OpcodeJumpIf() : base()
+ {
+ }
+
+ internal OpcodeJumpIf(int disp) : base(disp)
+ {
+ }
+
+ internal override void Run(CPU cpu)
+ {
+ TValue v = cpu.Pop();
+ if (v.Bool) {
+ base.Run(cpu);
+ }
+ }
+
+ internal override int StackAction {
+ get {
+ return -1;
+ }
+ }
+
+ internal override CodeElement ToCodeElement()
+ {
+ return new CodeElementJump(5);
+ }
+
+ public override string ToString()
+ {
+ if (JumpDisp == Int32.MinValue) {
+ return "jumpif UNRESOLVED";
+ } else {
+ return "jumpif disp=" + JumpDisp;
+ }
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+using System;
+using System.Collections.Generic;
+
+class OpcodeJumpIfNot : OpcodeJump {
+
+ internal OpcodeJumpIfNot() : base()
+ {
+ }
+
+ internal OpcodeJumpIfNot(int disp) : base(disp)
+ {
+ }
+
+ internal override void Run(CPU cpu)
+ {
+ TValue v = cpu.Pop();
+ if (!v.Bool) {
+ base.Run(cpu);
+ }
+ }
+
+ internal override int StackAction {
+ get {
+ return -1;
+ }
+ }
+
+ internal override CodeElement ToCodeElement()
+ {
+ return new CodeElementJump(6);
+ }
+
+ public override string ToString()
+ {
+ if (JumpDisp == Int32.MinValue) {
+ return "jumpifnot UNRESOLVED";
+ } else {
+ return "jumpifnot disp=" + JumpDisp;
+ }
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+using System;
+using System.Collections.Generic;
+
+class OpcodeJumpUncond : OpcodeJump {
+
+ internal OpcodeJumpUncond() : base()
+ {
+ }
+
+ internal OpcodeJumpUncond(int disp) : base(disp)
+ {
+ }
+
+ /*
+ * Unconditional jumps do not "fall through" unless they
+ * happen to be a jump to the next instruction...
+ */
+ internal override bool MayFallThrough {
+ get {
+ return JumpDisp == 0;
+ }
+ }
+
+ internal override CodeElement ToCodeElement()
+ {
+ return new CodeElementJump(4);
+ }
+
+ public override string ToString()
+ {
+ if (JumpDisp == Int32.MinValue) {
+ return "jump UNRESOLVED";
+ } else {
+ return "jump disp=" + JumpDisp;
+ }
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+using System;
+using System.Collections.Generic;
+
+class OpcodePutLocal : Opcode {
+
+ int num;
+
+ internal OpcodePutLocal(int num)
+ {
+ this.num = num;
+ }
+
+ internal override void Run(CPU cpu)
+ {
+ cpu.PutLocal(num, cpu.Pop());
+ }
+
+ internal override CodeElement ToCodeElement()
+ {
+ return new CodeElementUIntUInt(3, (uint)num);
+ }
+
+ internal override int StackAction {
+ get {
+ return -1;
+ }
+ }
+
+ public override string ToString()
+ {
+ return "putlocal " + num;
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+using System;
+using System.Collections.Generic;
+
+class OpcodeRet : Opcode {
+
+ internal override void Run(CPU cpu)
+ {
+ cpu.Exit();
+ }
+
+ internal override bool MayFallThrough {
+ get {
+ return false;
+ }
+ }
+
+ internal override CodeElement ToCodeElement()
+ {
+ return new CodeElementUInt(0);
+ }
+
+ public override string ToString()
+ {
+ return "ret";
+ }
+}
--- /dev/null
+using System;
+
+/*
+ * This structure contains the stack effect of a word: number of stack
+ * element consumed on input, and number of stack element produced on
+ * output.
+ */
+
+struct SType {
+
+ /*
+ * Get number of stack elements consumed on input; this is -1 if
+ * the stack effect is not known.
+ */
+ internal int DataIn {
+ get {
+ return din;
+ }
+ }
+
+ /*
+ * Get number of stack elements produced on output; this is -1 if
+ * either the stack effect is not known, or if the word never
+ * exits.
+ */
+ internal int DataOut {
+ get {
+ return dout;
+ }
+ }
+
+ /*
+ * Tell whether the stack effect is known.
+ */
+ internal bool IsKnown {
+ get {
+ return din >= 0;
+ }
+ }
+
+ /*
+ * Tell whether the stack effect is known and the word never exits.
+ */
+ internal bool NoExit {
+ get {
+ return din >= 0 && dout < 0;
+ }
+ }
+
+ int din, dout;
+
+ internal SType(int din, int dout)
+ {
+ if (din < 0) {
+ din = -1;
+ }
+ if (dout < 0) {
+ dout = -1;
+ }
+ this.din = din;
+ this.dout = dout;
+ }
+
+ /*
+ * Special value for the unknown stack effect.
+ */
+ internal static SType UNKNOWN = new SType(-1, -1);
+
+ /*
+ * Constant for the "blank stack effect".
+ */
+ internal static SType BLANK = new SType(0, 0);
+
+ public static bool operator ==(SType s1, SType s2)
+ {
+ return s1.din == s2.din && s1.dout == s2.dout;
+ }
+
+ public static bool operator !=(SType s1, SType s2)
+ {
+ return s1.din != s2.din || s1.dout != s2.dout;
+ }
+
+ public override bool Equals(Object obj)
+ {
+ return (obj is SType) && ((SType)obj == this);
+ }
+
+ public override int GetHashCode()
+ {
+ return din * 31 + dout * 17;
+ }
+
+ public override string ToString()
+ {
+ if (!IsKnown) {
+ return "UNKNOWN";
+ } else if (NoExit) {
+ return string.Format("in:{0},noexit", din);
+ } else {
+ return string.Format("in:{0},out:{1}", din, dout);
+ }
+ }
+
+ /*
+ * Test whether this stack effect is a sub-effect of the provided
+ * stack effect s. Stack effect s1 is a sub-effect of stack-effect
+ * s2 if any of the following holds:
+ * -- s1 and s2 are known, s1.din <= s2.din and s1 does not exit.
+ * -- s1 and s2 are known, s1.din <= s2.din, s1 and s2 exit,
+ * and s1.din - s1.dout == s2.din - s2.dout.
+ */
+ internal bool IsSubOf(SType s)
+ {
+ if (!IsKnown || !s.IsKnown) {
+ return false;
+ }
+ if (din > s.din) {
+ return false;
+ }
+ if (NoExit) {
+ return true;
+ }
+ if (s.NoExit) {
+ return false;
+ }
+ return (din - dout) == (s.din - s.dout);
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Text;
+
+/*
+ * This is the main compiler class.
+ */
+
+public class T0Comp {
+
+ /*
+ * Command-line entry point.
+ */
+ public static void Main(string[] args)
+ {
+ try {
+ List<string> r = new List<string>();
+ string outBase = null;
+ List<string> entryPoints = new List<string>();
+ string coreRun = null;
+ bool flow = true;
+ int dsLim = 32;
+ int rsLim = 32;
+ for (int i = 0; i < args.Length; i ++) {
+ string a = args[i];
+ if (!a.StartsWith("-")) {
+ r.Add(a);
+ continue;
+ }
+ if (a == "--") {
+ for (;;) {
+ if (++ i >= args.Length) {
+ break;
+ }
+ r.Add(args[i]);
+ }
+ break;
+ }
+ while (a.StartsWith("-")) {
+ a = a.Substring(1);
+ }
+ int j = a.IndexOf('=');
+ string pname;
+ string pval, pval2;
+ if (j < 0) {
+ pname = a.ToLowerInvariant();
+ pval = null;
+ pval2 = (i + 1) < args.Length
+ ? args[i + 1] : null;
+ } else {
+ pname = a.Substring(0, j).Trim()
+ .ToLowerInvariant();
+ pval = a.Substring(j + 1);
+ pval2 = null;
+ }
+ switch (pname) {
+ case "o":
+ case "out":
+ if (pval == null) {
+ if (pval2 == null) {
+ Usage();
+ }
+ i ++;
+ pval = pval2;
+ }
+ if (outBase != null) {
+ Usage();
+ }
+ outBase = pval;
+ break;
+ case "r":
+ case "run":
+ if (pval == null) {
+ if (pval2 == null) {
+ Usage();
+ }
+ i ++;
+ pval = pval2;
+ }
+ coreRun = pval;
+ break;
+ case "m":
+ case "main":
+ if (pval == null) {
+ if (pval2 == null) {
+ Usage();
+ }
+ i ++;
+ pval = pval2;
+ }
+ foreach (string ep in pval.Split(',')) {
+ string epz = ep.Trim();
+ if (epz.Length > 0) {
+ entryPoints.Add(epz);
+ }
+ }
+ break;
+ case "nf":
+ case "noflow":
+ flow = false;
+ break;
+ default:
+ Usage();
+ break;
+ }
+ }
+ if (r.Count == 0) {
+ Usage();
+ }
+ if (outBase == null) {
+ outBase = "t0out";
+ }
+ if (entryPoints.Count == 0) {
+ entryPoints.Add("main");
+ }
+ if (coreRun == null) {
+ coreRun = outBase;
+ }
+ T0Comp tc = new T0Comp();
+ tc.enableFlowAnalysis = flow;
+ tc.dsLimit = dsLim;
+ tc.rsLimit = rsLim;
+ using (TextReader tr = new StreamReader(
+ Assembly.GetExecutingAssembly()
+ .GetManifestResourceStream("t0-kernel")))
+ {
+ tc.ProcessInput(tr);
+ }
+ foreach (string a in r) {
+ Console.WriteLine("[{0}]", a);
+ using (TextReader tr = File.OpenText(a)) {
+ tc.ProcessInput(tr);
+ }
+ }
+ tc.Generate(outBase, coreRun, entryPoints.ToArray());
+ } catch (Exception e) {
+ Console.WriteLine(e.ToString());
+ Environment.Exit(1);
+ }
+ }
+
+ static void Usage()
+ {
+ Console.WriteLine(
+"usage: T0Comp.exe [ options... ] file...");
+ Console.WriteLine(
+"options:");
+ Console.WriteLine(
+" -o file use 'file' as base for output file name (default: 't0out')");
+ Console.WriteLine(
+" -r name use 'name' as base for run function (default: same as output)");
+ Console.WriteLine(
+" -m name[,name...]");
+ Console.WriteLine(
+" define entry point(s)");
+ Console.WriteLine(
+" -nf disable flow analysis");
+ Environment.Exit(1);
+ }
+
+ /*
+ * If 'delayedChar' is Int32.MinValue then there is no delayed
+ * character.
+ * If 'delayedChar' equals x >= 0 then there is one delayed
+ * character of value x.
+ * If 'delayedChar' equals y < 0 then there are two delayed
+ * characters, a newline (U+000A) followed by character of
+ * value -(y+1).
+ */
+ TextReader currentInput;
+ int delayedChar;
+
+ /*
+ * Common StringBuilder used to parse tokens; it is reused for
+ * each new token.
+ */
+ StringBuilder tokenBuilder;
+
+ /*
+ * There may be a delayed token in some cases.
+ */
+ String delayedToken;
+
+ /*
+ * Defined words are referenced by name in this map. Names are
+ * string-sensitive; for better reproducibility, the map is sorted
+ * (ordinal order).
+ */
+ IDictionary<string, Word> words;
+
+ /*
+ * Last defined word is also referenced in 'lastWord'. This is
+ * used by 'immediate'.
+ */
+ Word lastWord;
+
+ /*
+ * When compiling, this builder is used. A stack saves other
+ * builders in case of nested definition.
+ */
+ WordBuilder wordBuilder;
+ Stack<WordBuilder> savedWordBuilders;
+
+ /*
+ * C code defined for words is kept in this map, by word name.
+ */
+ IDictionary<string, string> allCCode;
+
+ /*
+ * 'compiling' is true when compiling tokens to a word, false
+ * when interpreting them.
+ */
+ bool compiling;
+
+ /*
+ * 'quitRunLoop' is set to true to trigger exit of the
+ * interpretation loop when the end of the current input file
+ * is reached.
+ */
+ bool quitRunLoop;
+
+ /*
+ * 'extraCode' is for C code that is to be added as preamble to
+ * the C output.
+ */
+ List<string> extraCode;
+
+ /*
+ * 'dataBlock' is the data block in which constant data bytes
+ * are accumulated.
+ */
+ ConstData dataBlock;
+
+ /*
+ * Counter for blocks of constant data.
+ */
+ long currentBlobID;
+
+ /*
+ * Flow analysis enable flag.
+ */
+ bool enableFlowAnalysis;
+
+ /*
+ * Data stack size limit.
+ */
+ int dsLimit;
+
+ /*
+ * Return stack size limit.
+ */
+ int rsLimit;
+
+ T0Comp()
+ {
+ tokenBuilder = new StringBuilder();
+ words = new SortedDictionary<string, Word>(
+ StringComparer.Ordinal);
+ savedWordBuilders = new Stack<WordBuilder>();
+ allCCode = new SortedDictionary<string, string>(
+ StringComparer.Ordinal);
+ compiling = false;
+ extraCode = new List<string>();
+ enableFlowAnalysis = true;
+
+ /*
+ * Native words are predefined and implemented only with
+ * native code. Some may be part of the generated output,
+ * if C code is set for them.
+ */
+
+ /*
+ * add-cc:
+ * Parses next token as a word name, then a C code snippet.
+ * Sets the C code for that word.
+ */
+ AddNative("add-cc:", false, SType.BLANK, cpu => {
+ string tt = Next();
+ if (tt == null) {
+ throw new Exception(
+ "EOF reached (missing name)");
+ }
+ if (allCCode.ContainsKey(tt)) {
+ throw new Exception(
+ "C code already set for: " + tt);
+ }
+ allCCode[tt] = ParseCCode();
+ });
+
+ /*
+ * cc:
+ * Parses next token as a word name, then a C code snippet.
+ * A new word is defined, that throws an exception when
+ * invoked during compilation. The C code is set for that
+ * new word.
+ */
+ AddNative("cc:", false, SType.BLANK, cpu => {
+ string tt = Next();
+ if (tt == null) {
+ throw new Exception(
+ "EOF reached (missing name)");
+ }
+ Word w = AddNative(tt, false, cpu2 => {
+ throw new Exception(
+ "C-only word: " + tt);
+ });
+ if (allCCode.ContainsKey(tt)) {
+ throw new Exception(
+ "C code already set for: " + tt);
+ }
+ SType stackEffect;
+ allCCode[tt] = ParseCCode(out stackEffect);
+ w.StackEffect = stackEffect;
+ });
+
+ /*
+ * preamble
+ * Parses a C code snippet, then adds it to the generated
+ * output preamble.
+ */
+ AddNative("preamble", false, SType.BLANK, cpu => {
+ extraCode.Add(ParseCCode());
+ });
+
+ /*
+ * make-CX
+ * Expects two integers and a string, and makes a
+ * constant that stands for the string as a C constant
+ * expression. The two integers are the expected range
+ * (min-max, inclusive).
+ */
+ AddNative("make-CX", false, new SType(3, 1), cpu => {
+ TValue c = cpu.Pop();
+ if (!(c.ptr is TPointerBlob)) {
+ throw new Exception(string.Format(
+ "'{0}' is not a string", c));
+ }
+ int max = cpu.Pop();
+ int min = cpu.Pop();
+ TValue tv = new TValue(0, new TPointerExpr(
+ c.ToString(), min, max));
+ cpu.Push(tv);
+ });
+
+ /*
+ * CX (immediate)
+ * Parses two integer constants, then a C code snippet.
+ * It then pushes on the stack, or compiles to the
+ * current word, a value consisting of the given C
+ * expression; the two integers indicate the expected
+ * range (min-max, inclusive) of the C expression when
+ * evaluated.
+ */
+ AddNative("CX", true, cpu => {
+ string tt = Next();
+ if (tt == null) {
+ throw new Exception(
+ "EOF reached (missing min value)");
+ }
+ int min = ParseInteger(tt);
+ tt = Next();
+ if (tt == null) {
+ throw new Exception(
+ "EOF reached (missing max value)");
+ }
+ int max = ParseInteger(tt);
+ if (max < min) {
+ throw new Exception("min/max in wrong order");
+ }
+ TValue tv = new TValue(0, new TPointerExpr(
+ ParseCCode().Trim(), min, max));
+ if (compiling) {
+ wordBuilder.Literal(tv);
+ } else {
+ cpu.Push(tv);
+ }
+ });
+
+ /*
+ * co
+ * Interrupt the current execution. This implements
+ * coroutines. It cannot be invoked during compilation.
+ */
+ AddNative("co", false, SType.BLANK, cpu => {
+ throw new Exception("No coroutine in compile mode");
+ });
+
+ /*
+ * :
+ * Parses next token as word name. It begins definition
+ * of that word, setting it as current target for
+ * word building. Any previously opened word is saved
+ * and will become available again as a target when that
+ * new word is finished building.
+ */
+ AddNative(":", false, cpu => {
+ string tt = Next();
+ if (tt == null) {
+ throw new Exception(
+ "EOF reached (missing name)");
+ }
+ if (compiling) {
+ savedWordBuilders.Push(wordBuilder);
+ } else {
+ compiling = true;
+ }
+ wordBuilder = new WordBuilder(this, tt);
+ tt = Next();
+ if (tt == null) {
+ throw new Exception(
+ "EOF reached (while compiling)");
+ }
+ if (tt == "(") {
+ SType stackEffect = ParseStackEffectNF();
+ if (!stackEffect.IsKnown) {
+ throw new Exception(
+ "Invalid stack effect syntax");
+ }
+ wordBuilder.StackEffect = stackEffect;
+ } else {
+ delayedToken = tt;
+ }
+ });
+
+ /*
+ * Pops a string as word name, and two integers as stack
+ * effect. It begins definition of that word, setting it
+ * as current target for word building. Any previously
+ * opened word is saved and will become available again as
+ * a target when that new word is finished building.
+ *
+ * Stack effect is the pair 'din dout'. If din is negative,
+ * then the stack effect is "unknown". If din is nonnegative
+ * but dout is negative, then the word is reputed never to
+ * return.
+ */
+ AddNative("define-word", false, cpu => {
+ int dout = cpu.Pop();
+ int din = cpu.Pop();
+ TValue s = cpu.Pop();
+ if (!(s.ptr is TPointerBlob)) {
+ throw new Exception(string.Format(
+ "Not a string: '{0}'", s));
+ }
+ string tt = s.ToString();
+ if (compiling) {
+ savedWordBuilders.Push(wordBuilder);
+ } else {
+ compiling = true;
+ }
+ wordBuilder = new WordBuilder(this, tt);
+ wordBuilder.StackEffect = new SType(din, dout);
+ });
+
+ /*
+ * ; (immediate)
+ * Ends current word. The current word is registered under
+ * its name, and the previously opened word (if any) becomes
+ * again the building target.
+ */
+ AddNative(";", true, cpu => {
+ if (!compiling) {
+ throw new Exception("Not compiling");
+ }
+ Word w = wordBuilder.Build();
+ string name = w.Name;
+ if (words.ContainsKey(name)) {
+ throw new Exception(
+ "Word already defined: " + name);
+ }
+ words[name] = w;
+ lastWord = w;
+ if (savedWordBuilders.Count > 0) {
+ wordBuilder = savedWordBuilders.Pop();
+ } else {
+ wordBuilder = null;
+ compiling = false;
+ }
+ });
+
+ /*
+ * immediate
+ * Sets the last defined word as immediate.
+ */
+ AddNative("immediate", false, cpu => {
+ if (lastWord == null) {
+ throw new Exception("No word defined yet");
+ }
+ lastWord.Immediate = true;
+ });
+
+ /*
+ * literal (immediate)
+ * Pops the current TOS value, and add in the current word
+ * the action of pushing that value. This cannot be used
+ * when no word is being built.
+ */
+ WordNative wliteral = AddNative("literal", true, cpu => {
+ CheckCompiling();
+ wordBuilder.Literal(cpu.Pop());
+ });
+
+ /*
+ * compile
+ * Pops the current TOS value, which must be an XT (pointer
+ * to a word); the action of calling that word is compiled
+ * in the current word.
+ */
+ WordNative wcompile = AddNative("compile", false, cpu => {
+ CheckCompiling();
+ wordBuilder.Call(cpu.Pop().ToXT());
+ });
+
+ /*
+ * postpone (immediate)
+ * Parses the next token as a word name, and add to the
+ * current word the action of calling that word. This
+ * basically removes immediatety from the next word.
+ */
+ AddNative("postpone", true, cpu => {
+ CheckCompiling();
+ string tt = Next();
+ if (tt == null) {
+ throw new Exception(
+ "EOF reached (missing name)");
+ }
+ TValue v;
+ bool isVal = TryParseLiteral(tt, out v);
+ Word w = LookupNF(tt);
+ if (isVal && w != null) {
+ throw new Exception(String.Format(
+ "Ambiguous: both defined word and"
+ + " literal: {0}", tt));
+ }
+ if (isVal) {
+ wordBuilder.Literal(v);
+ wordBuilder.CallExt(wliteral);
+ } else if (w != null) {
+ if (w.Immediate) {
+ wordBuilder.CallExt(w);
+ } else {
+ wordBuilder.Literal(new TValue(0,
+ new TPointerXT(w)));
+ wordBuilder.CallExt(wcompile);
+ }
+ } else {
+ wordBuilder.Literal(new TValue(0,
+ new TPointerXT(tt)));
+ wordBuilder.CallExt(wcompile);
+ }
+ });
+
+ /*
+ * Interrupt compilation with an error.
+ */
+ AddNative("exitvm", false, cpu => {
+ throw new Exception();
+ });
+
+ /*
+ * Open a new data block. Its symbolic address is pushed
+ * on the stack.
+ */
+ AddNative("new-data-block", false, cpu => {
+ dataBlock = new ConstData(this);
+ cpu.Push(new TValue(0, new TPointerBlob(dataBlock)));
+ });
+
+ /*
+ * Define a new data word. The data address and name are
+ * popped from the stack.
+ */
+ AddNative("define-data-word", false, cpu => {
+ string name = cpu.Pop().ToString();
+ TValue va = cpu.Pop();
+ TPointerBlob tb = va.ptr as TPointerBlob;
+ if (tb == null) {
+ throw new Exception(
+ "Address is not a data area");
+ }
+ Word w = new WordData(this, name, tb.Blob, va.x);
+ if (words.ContainsKey(name)) {
+ throw new Exception(
+ "Word already defined: " + name);
+ }
+ words[name] = w;
+ lastWord = w;
+ });
+
+ /*
+ * Get an address pointing at the end of the current
+ * data block. This is the address of the next byte that
+ * will be added.
+ */
+ AddNative("current-data", false, cpu => {
+ if (dataBlock == null) {
+ throw new Exception(
+ "No current data block");
+ }
+ cpu.Push(new TValue(dataBlock.Length,
+ new TPointerBlob(dataBlock)));
+ });
+
+ /*
+ * Add a byte value to the data block.
+ */
+ AddNative("data-add8", false, cpu => {
+ if (dataBlock == null) {
+ throw new Exception(
+ "No current data block");
+ }
+ int v = cpu.Pop();
+ if (v < 0 || v > 0xFF) {
+ throw new Exception(
+ "Byte value out of range: " + v);
+ }
+ dataBlock.Add8((byte)v);
+ });
+
+ /*
+ * Set a byte value in the data block.
+ */
+ AddNative("data-set8", false, cpu => {
+ TValue va = cpu.Pop();
+ TPointerBlob tb = va.ptr as TPointerBlob;
+ if (tb == null) {
+ throw new Exception(
+ "Address is not a data area");
+ }
+ int v = cpu.Pop();
+ if (v < 0 || v > 0xFF) {
+ throw new Exception(
+ "Byte value out of range: " + v);
+ }
+ tb.Blob.Set8(va.x, (byte)v);
+ });
+
+ /*
+ * Get a byte value from a data block.
+ */
+ AddNative("data-get8", false, new SType(1, 1), cpu => {
+ TValue va = cpu.Pop();
+ TPointerBlob tb = va.ptr as TPointerBlob;
+ if (tb == null) {
+ throw new Exception(
+ "Address is not a data area");
+ }
+ int v = tb.Blob.Read8(va.x);
+ cpu.Push(v);
+ });
+
+ /*
+ *
+ */
+ AddNative("compile-local-read", false, cpu => {
+ CheckCompiling();
+ wordBuilder.GetLocal(cpu.Pop().ToString());
+ });
+ AddNative("compile-local-write", false, cpu => {
+ CheckCompiling();
+ wordBuilder.PutLocal(cpu.Pop().ToString());
+ });
+
+ AddNative("ahead", true, cpu => {
+ CheckCompiling();
+ wordBuilder.Ahead();
+ });
+ AddNative("begin", true, cpu => {
+ CheckCompiling();
+ wordBuilder.Begin();
+ });
+ AddNative("again", true, cpu => {
+ CheckCompiling();
+ wordBuilder.Again();
+ });
+ AddNative("until", true, cpu => {
+ CheckCompiling();
+ wordBuilder.AgainIfNot();
+ });
+ AddNative("untilnot", true, cpu => {
+ CheckCompiling();
+ wordBuilder.AgainIf();
+ });
+ AddNative("if", true, cpu => {
+ CheckCompiling();
+ wordBuilder.AheadIfNot();
+ });
+ AddNative("ifnot", true, cpu => {
+ CheckCompiling();
+ wordBuilder.AheadIf();
+ });
+ AddNative("then", true, cpu => {
+ CheckCompiling();
+ wordBuilder.Then();
+ });
+ AddNative("cs-pick", false, cpu => {
+ CheckCompiling();
+ wordBuilder.CSPick(cpu.Pop());
+ });
+ AddNative("cs-roll", false, cpu => {
+ CheckCompiling();
+ wordBuilder.CSRoll(cpu.Pop());
+ });
+ AddNative("next-word", false, cpu => {
+ string s = Next();
+ if (s == null) {
+ throw new Exception("No next word (EOF)");
+ }
+ cpu.Push(StringToBlob(s));
+ });
+ AddNative("parse", false, cpu => {
+ int d = cpu.Pop();
+ string s = ReadTerm(d);
+ cpu.Push(StringToBlob(s));
+ });
+ AddNative("char", false, cpu => {
+ int c = NextChar();
+ if (c < 0) {
+ throw new Exception("No next character (EOF)");
+ }
+ cpu.Push(c);
+ });
+ AddNative("'", false, cpu => {
+ string name = Next();
+ cpu.Push(new TValue(0, new TPointerXT(name)));
+ });
+
+ /*
+ * The "execute" word is valid in generated C code, but
+ * since it jumps to a runtime pointer, its actual stack
+ * effect cannot be computed in advance.
+ */
+ AddNative("execute", false, cpu => {
+ cpu.Pop().Execute(this, cpu);
+ });
+
+ AddNative("[", true, cpu => {
+ CheckCompiling();
+ compiling = false;
+ });
+ AddNative("]", false, cpu => {
+ compiling = true;
+ });
+ AddNative("(local)", false, cpu => {
+ CheckCompiling();
+ wordBuilder.DefLocal(cpu.Pop().ToString());
+ });
+ AddNative("ret", true, cpu => {
+ CheckCompiling();
+ wordBuilder.Ret();
+ });
+
+ AddNative("drop", false, new SType(1, 0), cpu => {
+ cpu.Pop();
+ });
+ AddNative("dup", false, new SType(1, 2), cpu => {
+ cpu.Push(cpu.Peek(0));
+ });
+ AddNative("swap", false, new SType(2, 2), cpu => {
+ cpu.Rot(1);
+ });
+ AddNative("over", false, new SType(2, 3), cpu => {
+ cpu.Push(cpu.Peek(1));
+ });
+ AddNative("rot", false, new SType(3, 3), cpu => {
+ cpu.Rot(2);
+ });
+ AddNative("-rot", false, new SType(3, 3), cpu => {
+ cpu.NRot(2);
+ });
+
+ /*
+ * "roll" and "pick" are special in that the stack slot
+ * they inspect might be known only at runtime, so an
+ * absolute stack effect cannot be attributed. Instead,
+ * we simply hope that the caller knows what it is doing,
+ * and we use a simple stack effect for just the count
+ * value and picked value.
+ */
+ AddNative("roll", false, new SType(1, 0), cpu => {
+ cpu.Rot(cpu.Pop());
+ });
+ AddNative("pick", false, new SType(1, 1), cpu => {
+ cpu.Push(cpu.Peek(cpu.Pop()));
+ });
+
+ AddNative("+", false, new SType(2, 1), cpu => {
+ TValue b = cpu.Pop();
+ TValue a = cpu.Pop();
+ if (b.ptr == null) {
+ a.x += (int)b;
+ cpu.Push(a);
+ } else if (a.ptr is TPointerBlob
+ && b.ptr is TPointerBlob)
+ {
+ cpu.Push(StringToBlob(
+ a.ToString() + b.ToString()));
+ } else {
+ throw new Exception(string.Format(
+ "Cannot add '{0}' to '{1}'", b, a));
+ }
+ });
+ AddNative("-", false, new SType(2, 1), cpu => {
+ /*
+ * We can subtract two pointers, provided that
+ * they point to the same blob. Otherwise,
+ * the subtraction second operand must be an
+ * integer.
+ */
+ TValue b = cpu.Pop();
+ TValue a = cpu.Pop();
+ TPointerBlob ap = a.ptr as TPointerBlob;
+ TPointerBlob bp = b.ptr as TPointerBlob;
+ if (ap != null && bp != null && ap.Blob == bp.Blob) {
+ cpu.Push(new TValue(a.x - b.x));
+ return;
+ }
+ int bx = b;
+ a.x -= bx;
+ cpu.Push(a);
+ });
+ AddNative("neg", false, new SType(1, 1), cpu => {
+ int ax = cpu.Pop();
+ cpu.Push(-ax);
+ });
+ AddNative("*", false, new SType(2, 1), cpu => {
+ int bx = cpu.Pop();
+ int ax = cpu.Pop();
+ cpu.Push(ax * bx);
+ });
+ AddNative("/", false, new SType(2, 1), cpu => {
+ int bx = cpu.Pop();
+ int ax = cpu.Pop();
+ cpu.Push(ax / bx);
+ });
+ AddNative("u/", false, new SType(2, 1), cpu => {
+ uint bx = cpu.Pop();
+ uint ax = cpu.Pop();
+ cpu.Push(ax / bx);
+ });
+ AddNative("%", false, new SType(2, 1), cpu => {
+ int bx = cpu.Pop();
+ int ax = cpu.Pop();
+ cpu.Push(ax % bx);
+ });
+ AddNative("u%", false, new SType(2, 1), cpu => {
+ uint bx = cpu.Pop();
+ uint ax = cpu.Pop();
+ cpu.Push(ax % bx);
+ });
+ AddNative("<", false, new SType(2, 1), cpu => {
+ int bx = cpu.Pop();
+ int ax = cpu.Pop();
+ cpu.Push(ax < bx);
+ });
+ AddNative("<=", false, new SType(2, 1), cpu => {
+ int bx = cpu.Pop();
+ int ax = cpu.Pop();
+ cpu.Push(ax <= bx);
+ });
+ AddNative(">", false, new SType(2, 1), cpu => {
+ int bx = cpu.Pop();
+ int ax = cpu.Pop();
+ cpu.Push(ax > bx);
+ });
+ AddNative(">=", false, new SType(2, 1), cpu => {
+ int bx = cpu.Pop();
+ int ax = cpu.Pop();
+ cpu.Push(ax >= bx);
+ });
+ AddNative("=", false, new SType(2, 1), cpu => {
+ TValue b = cpu.Pop();
+ TValue a = cpu.Pop();
+ cpu.Push(a.Equals(b));
+ });
+ AddNative("<>", false, new SType(2, 1), cpu => {
+ TValue b = cpu.Pop();
+ TValue a = cpu.Pop();
+ cpu.Push(!a.Equals(b));
+ });
+ AddNative("u<", false, new SType(2, 1), cpu => {
+ uint bx = cpu.Pop().UInt;
+ uint ax = cpu.Pop().UInt;
+ cpu.Push(new TValue(ax < bx));
+ });
+ AddNative("u<=", false, new SType(2, 1), cpu => {
+ uint bx = cpu.Pop().UInt;
+ uint ax = cpu.Pop().UInt;
+ cpu.Push(new TValue(ax <= bx));
+ });
+ AddNative("u>", false, new SType(2, 1), cpu => {
+ uint bx = cpu.Pop().UInt;
+ uint ax = cpu.Pop().UInt;
+ cpu.Push(new TValue(ax > bx));
+ });
+ AddNative("u>=", false, new SType(2, 1), cpu => {
+ uint bx = cpu.Pop();
+ uint ax = cpu.Pop();
+ cpu.Push(ax >= bx);
+ });
+ AddNative("and", false, new SType(2, 1), cpu => {
+ uint bx = cpu.Pop();
+ uint ax = cpu.Pop();
+ cpu.Push(ax & bx);
+ });
+ AddNative("or", false, new SType(2, 1), cpu => {
+ uint bx = cpu.Pop();
+ uint ax = cpu.Pop();
+ cpu.Push(ax | bx);
+ });
+ AddNative("xor", false, new SType(2, 1), cpu => {
+ uint bx = cpu.Pop();
+ uint ax = cpu.Pop();
+ cpu.Push(ax ^ bx);
+ });
+ AddNative("not", false, new SType(1, 1), cpu => {
+ uint ax = cpu.Pop();
+ cpu.Push(~ax);
+ });
+ AddNative("<<", false, new SType(2, 1), cpu => {
+ int count = cpu.Pop();
+ if (count < 0 || count > 31) {
+ throw new Exception("Invalid shift count");
+ }
+ uint ax = cpu.Pop();
+ cpu.Push(ax << count);
+ });
+ AddNative(">>", false, new SType(2, 1), cpu => {
+ int count = cpu.Pop();
+ if (count < 0 || count > 31) {
+ throw new Exception("Invalid shift count");
+ }
+ int ax = cpu.Pop();
+ cpu.Push(ax >> count);
+ });
+ AddNative("u>>", false, new SType(2, 1), cpu => {
+ int count = cpu.Pop();
+ if (count < 0 || count > 31) {
+ throw new Exception("Invalid shift count");
+ }
+ uint ax = cpu.Pop();
+ cpu.Push(ax >> count);
+ });
+
+ AddNative(".", false, new SType(1, 0), cpu => {
+ Console.Write(" {0}", cpu.Pop().ToString());
+ });
+ AddNative(".s", false, SType.BLANK, cpu => {
+ int n = cpu.Depth;
+ for (int i = n - 1; i >= 0; i --) {
+ Console.Write(" {0}", cpu.Peek(i).ToString());
+ }
+ });
+ AddNative("putc", false, new SType(1, 0), cpu => {
+ Console.Write((char)cpu.Pop());
+ });
+ AddNative("puts", false, new SType(1, 0), cpu => {
+ Console.Write("{0}", cpu.Pop().ToString());
+ });
+ AddNative("cr", false, SType.BLANK, cpu => {
+ Console.WriteLine();
+ });
+ AddNative("eqstr", false, new SType(2, 1), cpu => {
+ string s2 = cpu.Pop().ToString();
+ string s1 = cpu.Pop().ToString();
+ cpu.Push(s1 == s2);
+ });
+ }
+
+ WordNative AddNative(string name, bool immediate,
+ WordNative.NativeRun code)
+ {
+ return AddNative(name, immediate, SType.UNKNOWN, code);
+ }
+
+ WordNative AddNative(string name, bool immediate, SType stackEffect,
+ WordNative.NativeRun code)
+ {
+ if (words.ContainsKey(name)) {
+ throw new Exception(
+ "Word already defined: " + name);
+ }
+ WordNative w = new WordNative(this, name, code);
+ w.Immediate = immediate;
+ w.StackEffect = stackEffect;
+ words[name] = w;
+ return w;
+ }
+
+ internal long NextBlobID()
+ {
+ return currentBlobID ++;
+ }
+
+ int NextChar()
+ {
+ int c = delayedChar;
+ if (c >= 0) {
+ delayedChar = Int32.MinValue;
+ } else if (c > Int32.MinValue) {
+ delayedChar = -(c + 1);
+ c = '\n';
+ } else {
+ c = currentInput.Read();
+ }
+ if (c == '\r') {
+ if (delayedChar >= 0) {
+ c = delayedChar;
+ delayedChar = Int32.MinValue;
+ } else {
+ c = currentInput.Read();
+ }
+ if (c != '\n') {
+ delayedChar = c;
+ c = '\n';
+ }
+ }
+ return c;
+ }
+
+ /*
+ * Un-read the character value 'c'. That value MUST be the one
+ * that was obtained from NextChar().
+ */
+ void Unread(int c)
+ {
+ if (c < 0) {
+ return;
+ }
+ if (delayedChar < 0) {
+ if (delayedChar != Int32.MinValue) {
+ throw new Exception(
+ "Already two delayed characters");
+ }
+ delayedChar = c;
+ } else if (c != '\n') {
+ throw new Exception("Cannot delay two characters");
+ } else {
+ delayedChar = -(delayedChar + 1);
+ }
+ }
+
+ string Next()
+ {
+ string r = delayedToken;
+ if (r != null) {
+ delayedToken = null;
+ return r;
+ }
+ tokenBuilder.Length = 0;
+ int c;
+ for (;;) {
+ c = NextChar();
+ if (c < 0) {
+ return null;
+ }
+ if (!IsWS(c)) {
+ break;
+ }
+ }
+ if (c == '"') {
+ return ParseString();
+ }
+ for (;;) {
+ tokenBuilder.Append((char)c);
+ c = NextChar();
+ if (c < 0 || IsWS(c)) {
+ Unread(c);
+ return tokenBuilder.ToString();
+ }
+ }
+ }
+
+ string ParseCCode()
+ {
+ SType stackEffect;
+ string r = ParseCCode(out stackEffect);
+ if (stackEffect.IsKnown) {
+ throw new Exception(
+ "Stack effect forbidden in this declaration");
+ }
+ return r;
+ }
+
+ string ParseCCode(out SType stackEffect)
+ {
+ string s = ParseCCodeNF(out stackEffect);
+ if (s == null) {
+ throw new Exception("Error while parsing C code");
+ }
+ return s;
+ }
+
+ string ParseCCodeNF(out SType stackEffect)
+ {
+ stackEffect = SType.UNKNOWN;
+ for (;;) {
+ int c = NextChar();
+ if (c < 0) {
+ return null;
+ }
+ if (!IsWS(c)) {
+ if (c == '(') {
+ if (stackEffect.IsKnown) {
+ Unread(c);
+ return null;
+ }
+ stackEffect = ParseStackEffectNF();
+ if (!stackEffect.IsKnown) {
+ return null;
+ }
+ continue;
+ } else if (c != '{') {
+ Unread(c);
+ return null;
+ }
+ break;
+ }
+ }
+ StringBuilder sb = new StringBuilder();
+ int count = 1;
+ for (;;) {
+ int c = NextChar();
+ if (c < 0) {
+ return null;
+ }
+ switch (c) {
+ case '{':
+ count ++;
+ break;
+ case '}':
+ if (-- count == 0) {
+ return sb.ToString();
+ }
+ break;
+ }
+ sb.Append((char)c);
+ }
+ }
+
+ /*
+ * Parse a stack effect declaration. This method assumes that the
+ * opening parenthesis has just been read. If the parsing fails,
+ * then this method returns SType.UNKNOWN.
+ */
+ SType ParseStackEffectNF()
+ {
+ bool seenSep = false;
+ bool seenBang = false;
+ int din = 0, dout = 0;
+ for (;;) {
+ string t = Next();
+ if (t == null) {
+ return SType.UNKNOWN;
+ }
+ if (t == "--") {
+ if (seenSep) {
+ return SType.UNKNOWN;
+ }
+ seenSep = true;
+ } else if (t == ")") {
+ if (seenSep) {
+ if (seenBang && dout == 1) {
+ dout = -1;
+ }
+ return new SType(din, dout);
+ } else {
+ return SType.UNKNOWN;
+ }
+ } else {
+ if (seenSep) {
+ if (dout == 0 && t == "!") {
+ seenBang = true;
+ }
+ dout ++;
+ } else {
+ din ++;
+ }
+ }
+ }
+ }
+
+ string ParseString()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.Append('"');
+ bool lcwb = false;
+ int hexNum = 0;
+ int acc = 0;
+ for (;;) {
+ int c = NextChar();
+ if (c < 0) {
+ throw new Exception(
+ "Unfinished literal string");
+ }
+ if (hexNum > 0) {
+ int d = HexVal(c);
+ if (d < 0) {
+ throw new Exception(String.Format(
+ "not an hex digit: U+{0:X4}",
+ c));
+ }
+ acc = (acc << 4) + d;
+ if (-- hexNum == 0) {
+ sb.Append((char)acc);
+ acc = 0;
+ }
+ } else if (lcwb) {
+ lcwb = false;
+ switch (c) {
+ case '\n': SkipNL(); break;
+ case 'x':
+ hexNum = 2;
+ break;
+ case 'u':
+ hexNum = 4;
+ break;
+ default:
+ sb.Append(SingleCharEscape(c));
+ break;
+ }
+ } else {
+ switch (c) {
+ case '"':
+ return sb.ToString();
+ case '\\':
+ lcwb = true;
+ break;
+ default:
+ sb.Append((char)c);
+ break;
+ }
+ }
+ }
+ }
+
+ static char SingleCharEscape(int c)
+ {
+ switch (c) {
+ case 'n': return '\n';
+ case 'r': return '\r';
+ case 't': return '\t';
+ case 's': return ' ';
+ default:
+ return (char)c;
+ }
+ }
+
+ /*
+ * A backslash+newline sequence occurred in a literal string; we
+ * check and consume the newline escape sequence (whitespace at
+ * start of next line, then a double-quote character).
+ */
+ void SkipNL()
+ {
+ for (;;) {
+ int c = NextChar();
+ if (c < 0) {
+ throw new Exception("EOF in literal string");
+ }
+ if (c == '\n') {
+ throw new Exception(
+ "Unescaped newline in literal string");
+ }
+ if (IsWS(c)) {
+ continue;
+ }
+ if (c == '"') {
+ return;
+ }
+ throw new Exception(
+ "Invalid newline escape in literal string");
+ }
+ }
+
+ static char DecodeCharConst(string t)
+ {
+ if (t.Length == 1 && t[0] != '\\') {
+ return t[0];
+ }
+ if (t.Length >= 2 && t[0] == '\\') {
+ switch (t[1]) {
+ case 'x':
+ if (t.Length == 4) {
+ int x = DecHex(t.Substring(2));
+ if (x >= 0) {
+ return (char)x;
+ }
+ }
+ break;
+ case 'u':
+ if (t.Length == 6) {
+ int x = DecHex(t.Substring(2));
+ if (x >= 0) {
+ return (char)x;
+ }
+ }
+ break;
+ default:
+ if (t.Length == 2) {
+ return SingleCharEscape(t[1]);
+ }
+ break;
+ }
+ }
+ throw new Exception("Invalid literal char: `" + t);
+ }
+
+ static int DecHex(string s)
+ {
+ int acc = 0;
+ foreach (char c in s) {
+ int d = HexVal(c);
+ if (d < 0) {
+ return -1;
+ }
+ acc = (acc << 4) + d;
+ }
+ return acc;
+ }
+
+ static int HexVal(int c)
+ {
+ if (c >= '0' && c <= '9') {
+ return c - '0';
+ } else if (c >= 'A' && c <= 'F') {
+ return c - ('A' - 10);
+ } else if (c >= 'a' && c <= 'f') {
+ return c - ('a' - 10);
+ } else {
+ return -1;
+ }
+ }
+
+ string ReadTerm(int ct)
+ {
+ StringBuilder sb = new StringBuilder();
+ for (;;) {
+ int c = NextChar();
+ if (c < 0) {
+ throw new Exception(String.Format(
+ "EOF reached before U+{0:X4}", ct));
+ }
+ if (c == ct) {
+ return sb.ToString();
+ }
+ sb.Append((char)c);
+ }
+ }
+
+ static bool IsWS(int c)
+ {
+ return c <= 32;
+ }
+
+ void ProcessInput(TextReader tr)
+ {
+ this.currentInput = tr;
+ delayedChar = -1;
+ Word w = new WordNative(this, "toplevel",
+ xcpu => { CompileStep(xcpu); });
+ CPU cpu = new CPU();
+ Opcode[] code = new Opcode[] {
+ new OpcodeCall(w),
+ new OpcodeJumpUncond(-2)
+ };
+ quitRunLoop = false;
+ cpu.Enter(code, 0);
+ for (;;) {
+ if (quitRunLoop) {
+ break;
+ }
+ Opcode op = cpu.ipBuf[cpu.ipOff ++];
+ op.Run(cpu);
+ }
+ }
+
+ void CompileStep(CPU cpu)
+ {
+ string tt = Next();
+ if (tt == null) {
+ if (compiling) {
+ throw new Exception("EOF while compiling");
+ }
+ quitRunLoop = true;
+ return;
+ }
+ TValue v;
+ bool isVal = TryParseLiteral(tt, out v);
+ Word w = LookupNF(tt);
+ if (isVal && w != null) {
+ throw new Exception(String.Format(
+ "Ambiguous: both defined word and literal: {0}",
+ tt));
+ }
+ if (compiling) {
+ if (isVal) {
+ wordBuilder.Literal(v);
+ } else if (w != null) {
+ if (w.Immediate) {
+ w.Run(cpu);
+ } else {
+ wordBuilder.CallExt(w);
+ }
+ } else {
+ wordBuilder.Call(tt);
+ }
+ } else {
+ if (isVal) {
+ cpu.Push(v);
+ } else if (w != null) {
+ w.Run(cpu);
+ } else {
+ throw new Exception(String.Format(
+ "Unknown word: '{0}'", tt));
+ }
+ }
+ }
+
+ string GetCCode(string name)
+ {
+ string ccode;
+ allCCode.TryGetValue(name, out ccode);
+ return ccode;
+ }
+
+ void Generate(string outBase, string coreRun,
+ params string[] entryPoints)
+ {
+ /*
+ * Gather all words that are part of the generated
+ * code. This is done by exploring references
+ * transitively. All such words are thus implicitly
+ * resolved.
+ */
+ IDictionary<string, Word> wordSet =
+ new SortedDictionary<string, Word>(
+ StringComparer.Ordinal);
+ Queue<Word> tx = new Queue<Word>();
+ foreach (string ep in entryPoints) {
+ if (wordSet.ContainsKey(ep)) {
+ continue;
+ }
+ Word w = Lookup(ep);
+ wordSet[w.Name] = w;
+ tx.Enqueue(w);
+ }
+ while (tx.Count > 0) {
+ Word w = tx.Dequeue();
+ foreach (Word w2 in w.GetReferences()) {
+ if (wordSet.ContainsKey(w2.Name)) {
+ continue;
+ }
+ wordSet[w2.Name] = w2;
+ tx.Enqueue(w2);
+ }
+ }
+
+ /*
+ * Do flow analysis.
+ */
+ if (enableFlowAnalysis) {
+ foreach (string ep in entryPoints) {
+ Word w = wordSet[ep];
+ w.AnalyseFlow();
+ Console.WriteLine("{0}: ds={1} rs={2}",
+ ep, w.MaxDataStack, w.MaxReturnStack);
+ if (w.MaxDataStack > dsLimit) {
+ throw new Exception("'" + ep
+ + "' exceeds data stack limit");
+ }
+ if (w.MaxReturnStack > rsLimit) {
+ throw new Exception("'" + ep
+ + "' exceeds return stack"
+ + " limit");
+ }
+ }
+ }
+
+ /*
+ * Gather referenced data areas and compute their
+ * addresses in the generated data block. The address
+ * 0 in the data block is unaffected so that no
+ * valid runtime pointer is equal to null.
+ */
+ IDictionary<long, ConstData> blocks =
+ new SortedDictionary<long, ConstData>();
+ foreach (Word w in wordSet.Values) {
+ foreach (ConstData cd in w.GetDataBlocks()) {
+ blocks[cd.ID] = cd;
+ }
+ }
+ int dataLen = 1;
+ foreach (ConstData cd in blocks.Values) {
+ cd.Address = dataLen;
+ dataLen += cd.Length;
+ }
+
+ /*
+ * Generated code is a sequence of "slot numbers", each
+ * referencing either a piece of explicit C code, or an
+ * entry in the table of interpreted words.
+ *
+ * Opcodes other than "call" get the slots 0 to 6:
+ *
+ * 0 ret no argument
+ * 1 const signed value
+ * 2 get local local number
+ * 3 put local local number
+ * 4 jump signed offset
+ * 5 jump if signed offset
+ * 6 jump if not signed offset
+ *
+ * The argument, if any, is in "7E" format: the value is
+ * encoded in 7-bit chunk, with big-endian signed
+ * convention. Each 7-bit chunk is encoded over one byte;
+ * the upper bit is 1 for all chunks except the last one.
+ *
+ * Words with explicit C code get the slot numbers
+ * immediately after 6. Interpreted words come afterwards.
+ */
+ IDictionary<string, int> slots = new Dictionary<string, int>();
+ int curSlot = 7;
+
+ /*
+ * Get explicit C code for words which have such code.
+ * We use string equality on C code so that words with
+ * identical implementations get merged.
+ *
+ * We also check that words with no explicit C code are
+ * interpreted.
+ */
+ IDictionary<string, int> ccodeUni =
+ new Dictionary<string, int>();
+ IDictionary<int, string> ccodeNames =
+ new Dictionary<int, string>();
+ foreach (Word w in wordSet.Values) {
+ string ccode = GetCCode(w.Name);
+ if (ccode == null) {
+ if (w is WordNative) {
+ throw new Exception(String.Format(
+ "No C code for native '{0}'",
+ w.Name));
+ }
+ continue;
+ }
+ int sn;
+ if (ccodeUni.ContainsKey(ccode)) {
+ sn = ccodeUni[ccode];
+ ccodeNames[sn] += " " + EscapeCComment(w.Name);
+ } else {
+ sn = curSlot ++;
+ ccodeUni[ccode] = sn;
+ ccodeNames[sn] = EscapeCComment(w.Name);
+ }
+ slots[w.Name] = sn;
+ w.Slot = sn;
+ }
+
+ /*
+ * Assign slot values to all remaining words; we know they
+ * are all interpreted.
+ */
+ int slotInterpreted = curSlot;
+ foreach (Word w in wordSet.Values) {
+ if (GetCCode(w.Name) != null) {
+ continue;
+ }
+ int sn = curSlot ++;
+ slots[w.Name] = sn;
+ w.Slot = sn;
+ }
+ int numInterpreted = curSlot - slotInterpreted;
+
+ /*
+ * Verify that all entry points are interpreted words.
+ */
+ foreach (string ep in entryPoints) {
+ if (GetCCode(ep) != null) {
+ throw new Exception(
+ "Non-interpreted entry point");
+ }
+ }
+
+ /*
+ * Compute the code block. Each word (without any C code)
+ * yields some CodeElement instances.
+ */
+ List<CodeElement> gcodeList = new List<CodeElement>();
+ CodeElement[] interpretedEntry =
+ new CodeElement[numInterpreted];
+ foreach (Word w in wordSet.Values) {
+ if (GetCCode(w.Name) != null) {
+ continue;
+ }
+ int n = gcodeList.Count;
+ w.GenerateCodeElements(gcodeList);
+ interpretedEntry[w.Slot - slotInterpreted] =
+ gcodeList[n];
+ }
+ CodeElement[] gcode = gcodeList.ToArray();
+
+ /*
+ * Compute all addresses and offsets. This loops until
+ * the addresses stabilize.
+ */
+ int totalLen = -1;
+ int[] gcodeLen = new int[gcode.Length];
+ for (;;) {
+ for (int i = 0; i < gcode.Length; i ++) {
+ gcodeLen[i] = gcode[i].Length;
+ }
+ int off = 0;
+ for (int i = 0; i < gcode.Length; i ++) {
+ gcode[i].Address = off;
+ gcode[i].LastLength = gcodeLen[i];
+ off += gcodeLen[i];
+ }
+ if (off == totalLen) {
+ break;
+ }
+ totalLen = off;
+ }
+
+ /*
+ * Produce output file.
+ */
+ using (TextWriter tw = File.CreateText(outBase + ".c")) {
+ tw.NewLine = "\n";
+
+ tw.WriteLine("{0}",
+@"/* 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 uint8_t t0_datablock[];
+");
+
+ /*
+ * Add declarations (not definitions) for the
+ * entry point initialisation functions, and the
+ * runner.
+ */
+ tw.WriteLine();
+ foreach (string ep in entryPoints) {
+ tw.WriteLine("void {0}_init_{1}(void *t0ctx);",
+ coreRun, ep);
+ }
+ tw.WriteLine();
+ tw.WriteLine("void {0}_run(void *t0ctx);", coreRun);
+
+ /*
+ * Add preamble elements here. They may be needed
+ * for evaluating constant expressions in the
+ * code block.
+ */
+ foreach (string pp in extraCode) {
+ tw.WriteLine();
+ tw.WriteLine("{0}", pp);
+ }
+
+ BlobWriter bw;
+ tw.WriteLine();
+ tw.Write("static const uint8_t t0_datablock[] = {");
+ bw = new BlobWriter(tw, 78, 1);
+ bw.Append((byte)0);
+ foreach (ConstData cd in blocks.Values) {
+ cd.Encode(bw);
+ }
+ tw.WriteLine();
+ tw.WriteLine("};");
+
+ tw.WriteLine();
+ tw.Write("static const uint8_t t0_codeblock[] = {");
+ bw = new BlobWriter(tw, 78, 1);
+ foreach (CodeElement ce in gcode) {
+ ce.Encode(bw);
+ }
+ tw.WriteLine();
+ tw.WriteLine("};");
+
+ tw.WriteLine();
+ tw.Write("static const uint16_t t0_caddr[] = {");
+ for (int i = 0; i < interpretedEntry.Length; i ++) {
+ if (i != 0) {
+ tw.Write(',');
+ }
+ tw.WriteLine();
+ tw.Write("\t{0}", interpretedEntry[i].Address);
+ }
+ tw.WriteLine();
+ tw.WriteLine("};");
+
+ tw.WriteLine();
+ tw.WriteLine("#define T0_INTERPRETED {0}",
+ slotInterpreted);
+ tw.WriteLine();
+ tw.WriteLine("{0}",
+@"#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)");
+ tw.WriteLine();
+ tw.WriteLine("{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); \
+}");
+
+ tw.WriteLine();
+ foreach (string ep in entryPoints) {
+ tw.WriteLine("T0_DEFENTRY({0}, {1})",
+ coreRun + "_init_" + ep,
+ wordSet[ep].Slot);
+ }
+ tw.WriteLine();
+ tw.WriteLine("void");
+ tw.WriteLine("{0}_run(void *t0ctx)", coreRun);
+ tw.WriteLine("{0}",
+@"{
+ 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() break
+
+ dp = ((t0_context *)t0ctx)->dp;
+ rp = ((t0_context *)t0ctx)->rp;
+ ip = ((t0_context *)t0ctx)->ip;
+ for (;;) {
+ uint32_t t0x;
+
+ t0x = t0_parse7E_unsigned(&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;");
+
+ SortedDictionary<int, string> nccode =
+ new SortedDictionary<int, string>();
+ foreach (string k in ccodeUni.Keys) {
+ nccode[ccodeUni[k]] = k;
+ }
+ foreach (int sn in nccode.Keys) {
+ tw.WriteLine(
+@" case {0}: {{
+ /* {1} */
+{2}
+ }}
+ break;", sn, ccodeNames[sn], nccode[sn]);
+ }
+
+ tw.WriteLine(
+@" }
+
+ } else {
+ T0_ENTER(ip, rp, t0x);
+ }
+ }
+t0_exit:
+ ((t0_context *)t0ctx)->dp = dp;
+ ((t0_context *)t0ctx)->rp = rp;
+ ((t0_context *)t0ctx)->ip = ip;
+}");
+ }
+
+ int codeLen = 0;
+ foreach (CodeElement ce in gcode) {
+ codeLen += ce.Length;
+ }
+ int dataBlockLen = 0;
+ foreach (ConstData cd in blocks.Values) {
+ dataBlockLen += cd.Length;
+ }
+
+ /*
+ * Write some statistics on produced code.
+ */
+ Console.WriteLine("code length: {0,6} byte(s)", codeLen);
+ Console.WriteLine("data length: {0,6} byte(s)", dataLen);
+ Console.WriteLine("interpreted words: {0}",
+ interpretedEntry.Length);
+ }
+
+ internal Word Lookup(string name)
+ {
+ Word w = LookupNF(name);
+ if (w != null) {
+ return w;
+ }
+ throw new Exception(String.Format("No such word: '{0}'", name));
+ }
+
+ internal Word LookupNF(string name)
+ {
+ Word w;
+ words.TryGetValue(name, out w);
+ return w;
+ }
+
+ internal TValue StringToBlob(string s)
+ {
+ return new TValue(0, new TPointerBlob(this, s));
+ }
+
+ internal bool TryParseLiteral(string tt, out TValue tv)
+ {
+ tv = new TValue(0);
+ if (tt.StartsWith("\"")) {
+ tv = StringToBlob(tt.Substring(1));
+ return true;
+ }
+ if (tt.StartsWith("`")) {
+ tv = DecodeCharConst(tt.Substring(1));
+ return true;
+ }
+ bool neg = false;
+ if (tt.StartsWith("-")) {
+ neg = true;
+ tt = tt.Substring(1);
+ } else if (tt.StartsWith("+")) {
+ tt = tt.Substring(1);
+ }
+ uint radix = 10;
+ if (tt.StartsWith("0x") || tt.StartsWith("0X")) {
+ radix = 16;
+ tt = tt.Substring(2);
+ } else if (tt.StartsWith("0b") || tt.StartsWith("0B")) {
+ radix = 2;
+ tt = tt.Substring(2);
+ }
+ if (tt.Length == 0) {
+ return false;
+ }
+ uint acc = 0;
+ bool overflow = false;
+ uint maxV = uint.MaxValue / radix;
+ foreach (char c in tt) {
+ int d = HexVal(c);
+ if (d < 0 || d >= radix) {
+ return false;
+ }
+ if (acc > maxV) {
+ overflow = true;
+ }
+ acc *= radix;
+ if ((uint)d > uint.MaxValue - acc) {
+ overflow = true;
+ }
+ acc += (uint)d;
+ }
+ int x = (int)acc;
+ if (neg) {
+ if (acc > (uint)0x80000000) {
+ overflow = true;
+ }
+ x = -x;
+ }
+ if (overflow) {
+ throw new Exception(
+ "invalid literal integer (overflow)");
+ }
+ tv = x;
+ return true;
+ }
+
+ int ParseInteger(string tt)
+ {
+ TValue tv;
+ if (!TryParseLiteral(tt, out tv)) {
+ throw new Exception("not an integer: " + ToString());
+ }
+ return (int)tv;
+ }
+
+ void CheckCompiling()
+ {
+ if (!compiling) {
+ throw new Exception("Not in compilation mode");
+ }
+ }
+
+ static string EscapeCComment(string s)
+ {
+ StringBuilder sb = new StringBuilder();
+ foreach (char c in s) {
+ if (c >= 33 && c <= 126 && c != '%') {
+ sb.Append(c);
+ } else if (c < 0x100) {
+ sb.AppendFormat("%{0:X2}", (int)c);
+ } else if (c < 0x800) {
+ sb.AppendFormat("%{0:X2}%{0:X2}",
+ ((int)c >> 6) | 0xC0,
+ ((int)c & 0x3F) | 0x80);
+ } else {
+ sb.AppendFormat("%{0:X2}%{0:X2}%{0:X2}",
+ ((int)c >> 12) | 0xE0,
+ (((int)c >> 6) & 0x3F) | 0x80,
+ ((int)c & 0x3F) | 0x80);
+ }
+ }
+ return sb.ToString().Replace("*/", "%2A/");
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+using System;
+using System.Collections.Generic;
+
+class TPointerBase {
+
+ /* obsolete
+ internal virtual TValue Get(TValue vp)
+ {
+ throw new Exception(
+ "cannot get values from this pointer");
+ }
+
+ internal virtual void Set(TValue vp, TValue nval)
+ {
+ throw new Exception(
+ "cannot set values to this pointer");
+ }
+ */
+
+ internal virtual bool ToBool(TValue vp)
+ {
+ return true;
+ }
+
+ internal virtual void Execute(T0Comp ctx, CPU cpu)
+ {
+ throw new Exception("value is not an xt: " + ToString());
+ }
+
+ internal virtual string ToString(TValue vp)
+ {
+ return String.Format("{0}+{1}",
+ GetType().Name, vp.x);
+ }
+
+ internal virtual bool Equals(TPointerBase tp)
+ {
+ return this == tp;
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+using System;
+using System.Collections.Generic;
+
+class TPointerBlob : TPointerBase {
+
+ internal ConstData Blob { get; private set; }
+
+ internal TPointerBlob(ConstData cd)
+ {
+ this.Blob = cd;
+ }
+
+ internal TPointerBlob(T0Comp owner, string s)
+ {
+ Blob = new ConstData(owner);
+ Blob.AddString(s);
+ }
+
+ /* obsolete
+ internal override TValue Get8(TValue vp)
+ {
+ return new TValue((int)Blob.Read8(vp.x));
+ }
+
+ internal override TValue Get16(TValue vp)
+ {
+ return new TValue((int)Blob.Read16(vp.x));
+ }
+
+ internal override TValue Get24(TValue vp)
+ {
+ return new TValue((int)Blob.Read24(vp.x));
+ }
+
+ internal override TValue Get32(TValue vp)
+ {
+ return new TValue((int)Blob.Read32(vp.x));
+ }
+ */
+
+ internal override string ToString(TValue vp)
+ {
+ return Blob.ToString(vp.x);
+ }
+
+ internal override bool Equals(TPointerBase tp)
+ {
+ TPointerBlob tb = tp as TPointerBlob;
+ return tb != null && Blob == tb.Blob;
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+using System;
+
+class TPointerExpr : TPointerBase {
+
+ string expr;
+ int min, max;
+
+ internal TPointerExpr(string expr, int min, int max)
+ {
+ this.expr = expr;
+ this.min = min;
+ this.max = max;
+ }
+
+ internal override bool ToBool(TValue vp)
+ {
+ throw new Exception("Cannot evaluate C-expr at compile time");
+ }
+
+ internal override string ToString(TValue vp)
+ {
+ return ToCExpr(vp.x);
+ }
+
+ internal string ToCExpr(int off)
+ {
+ if (off == 0) {
+ return expr;
+ } else if (off > 0) {
+ return String.Format(
+ "(uint32_t)({0}) + {1}", expr, off);
+ } else {
+ return String.Format(
+ "(uint32_t)({0}) - {1}", expr, -(long)off);
+ }
+ }
+
+ internal int GetMaxBitLength(int off)
+ {
+ long rmin = (long)min + off;
+ long rmax = (long)max + off;
+ int numBits = 1;
+ if (rmin < 0) {
+ numBits = Math.Max(numBits, BitLength(rmin));
+ }
+ if (rmax > 0) {
+ numBits = Math.Max(numBits, BitLength(rmax));
+ }
+ return Math.Min(numBits, 32);
+ }
+
+ /*
+ * Get the minimal bit length of a value. This is for a signed
+ * representation: the length includes a sign bit. Thus, the
+ * returned value will be at least 1.
+ */
+ static int BitLength(long v)
+ {
+ int num = 1;
+ if (v < 0) {
+ while (v != -1) {
+ num ++;
+ v >>= 1;
+ }
+ } else {
+ while (v != 0) {
+ num ++;
+ v >>= 1;
+ }
+ }
+ return num;
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+using System;
+using System.Collections.Generic;
+
+class TPointerNull : TPointerBase {
+
+ internal override bool ToBool(TValue vp)
+ {
+ return false;
+ }
+
+ internal override string ToString(TValue vp)
+ {
+ return "null";
+ }
+
+ internal override bool Equals(TPointerBase tp)
+ {
+ return tp is TPointerNull;
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+using System;
+using System.Collections.Generic;
+
+class TPointerXT : TPointerBase {
+
+ internal string Name {
+ get; private set;
+ }
+
+ internal Word Target {
+ get; private set;
+ }
+
+ internal TPointerXT(string name)
+ {
+ this.Name = name;
+ this.Target = null;
+ }
+
+ internal TPointerXT(Word target)
+ {
+ this.Name = target.Name;
+ this.Target = target;
+ }
+
+ internal void Resolve(T0Comp ctx)
+ {
+ if (Target == null) {
+ Target = ctx.Lookup(Name);
+ }
+ }
+
+ internal override void Execute(T0Comp ctx, CPU cpu)
+ {
+ Resolve(ctx);
+ Target.Run(cpu);
+ }
+
+ internal override string ToString(TValue vp)
+ {
+ return String.Format("<'{0}>", Name);
+ }
+
+ internal override bool Equals(TPointerBase tp)
+ {
+ TPointerXT tx = tp as TPointerXT;
+ return tx != null && Name == tx.Name;
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+using System;
+using System.Collections.Generic;
+
+/*
+ * Each value is represented with a TValue structure. Integers use the 'x'
+ * field, and 'ptr' is null; for pointers, the 'ptr' field is used, and the
+ * 'x' is then an offset in the object represented by 'ptr'.
+ */
+
+struct TValue {
+
+ internal int x;
+ internal TPointerBase ptr;
+
+ internal TValue(int x)
+ {
+ this.x = x;
+ this.ptr = null;
+ }
+
+ internal TValue(uint x)
+ {
+ this.x = (int)x;
+ this.ptr = null;
+ }
+
+ internal TValue(bool b)
+ {
+ this.x = b ? -1 : 0;
+ this.ptr = null;
+ }
+
+ internal TValue(int x, TPointerBase ptr)
+ {
+ this.x = x;
+ this.ptr = ptr;
+ }
+
+ /*
+ * Convert this value to a boolean; integer 0 and null pointer are
+ * 'false', other values are 'true'.
+ */
+ internal bool Bool {
+ get {
+ if (ptr == null) {
+ return x != 0;
+ } else {
+ return ptr.ToBool(this);
+ }
+ }
+ }
+
+ /*
+ * Get this value as an integer. Pointers cannot be converted to
+ * integers.
+ */
+ internal int Int {
+ get {
+ if (ptr == null) {
+ return x;
+ }
+ throw new Exception("not an integer: " + ToString());
+ }
+ }
+
+ /*
+ * Get this value as an unsigned integer. This is the integer
+ * value, reduced modulo 2^32 in the 0..2^32-1 range.
+ */
+ internal uint UInt {
+ get {
+ return (uint)Int;
+ }
+ }
+
+ /*
+ * String format of integers uses decimal representation. For
+ * pointers, this depends on the pointed-to value.
+ */
+ public override string ToString()
+ {
+ if (ptr == null) {
+ return String.Format("{0}", x);
+ } else {
+ return ptr.ToString(this);
+ }
+ }
+
+ /*
+ * If this value is an XT, then execute it. Otherwise, an exception
+ * is thrown.
+ */
+ internal void Execute(T0Comp ctx, CPU cpu)
+ {
+ ToXT().Execute(ctx, cpu);
+ }
+
+ /*
+ * Convert this value to an XT. On failure, an exception is thrown.
+ */
+ internal TPointerXT ToXT()
+ {
+ TPointerXT xt = ptr as TPointerXT;
+ if (xt == null) {
+ throw new Exception(
+ "value is not an xt: " + ToString());
+ }
+ return xt;
+ }
+
+ /*
+ * Compare this value to another.
+ */
+ internal bool Equals(TValue v)
+ {
+ if (x != v.x) {
+ return false;
+ }
+ if (ptr == v.ptr) {
+ return true;
+ }
+ if (ptr == null || v.ptr == null) {
+ return false;
+ }
+ return ptr.Equals(v.ptr);
+ }
+
+ public static implicit operator TValue(bool val)
+ {
+ return new TValue(val);
+ }
+
+ public static implicit operator TValue(sbyte val)
+ {
+ return new TValue((int)val);
+ }
+
+ public static implicit operator TValue(byte val)
+ {
+ return new TValue((int)val);
+ }
+
+ public static implicit operator TValue(short val)
+ {
+ return new TValue((int)val);
+ }
+
+ public static implicit operator TValue(ushort val)
+ {
+ return new TValue((int)val);
+ }
+
+ public static implicit operator TValue(char val)
+ {
+ return new TValue((int)val);
+ }
+
+ public static implicit operator TValue(int val)
+ {
+ return new TValue((int)val);
+ }
+
+ public static implicit operator TValue(uint val)
+ {
+ return new TValue((int)val);
+ }
+
+ public static implicit operator bool(TValue v)
+ {
+ return v.Bool;
+ }
+
+ public static implicit operator sbyte(TValue v)
+ {
+ return (sbyte)v.Int;
+ }
+
+ public static implicit operator byte(TValue v)
+ {
+ return (byte)v.Int;
+ }
+
+ public static implicit operator short(TValue v)
+ {
+ return (short)v.Int;
+ }
+
+ public static implicit operator ushort(TValue v)
+ {
+ return (ushort)v.Int;
+ }
+
+ public static implicit operator char(TValue v)
+ {
+ return (char)v.Int;
+ }
+
+ public static implicit operator int(TValue v)
+ {
+ return (int)v.Int;
+ }
+
+ public static implicit operator uint(TValue v)
+ {
+ return (uint)v.Int;
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+using System;
+using System.Collections.Generic;
+
+/*
+ * A "word" is a function with a name. Words can be either native or
+ * interpreted; native words are implemented as some in-compiler special
+ * code.
+ *
+ * Some native words (not all of them) have a C implementation and can
+ * thus be part of the generated C code. Native words with no C
+ * implementation can be used only during compilation; this is typically
+ * the case for words that support the syntax (e.g. 'if').
+ */
+
+abstract class Word {
+
+ /*
+ * The compiler context for this word.
+ */
+ internal T0Comp TC {
+ get; private set;
+ }
+
+ /*
+ * Immediate words are executed immediately when encountered in the
+ * source code, even while compiling another word.
+ */
+ internal bool Immediate {
+ get; set;
+ }
+
+ /*
+ * Each word has a unique name. Names are case-sensitive.
+ */
+ internal string Name {
+ get; private set;
+ }
+
+ /*
+ * Words are allocated slot numbers when output code is generated.
+ */
+ internal int Slot {
+ get; set;
+ }
+
+ /*
+ * Each word may have a known stack effect.
+ */
+ internal SType StackEffect {
+ get; set;
+ }
+
+ internal Word(T0Comp owner, string name)
+ {
+ TC = owner;
+ Name = name;
+ StackEffect = SType.UNKNOWN;
+ }
+
+ /*
+ * Resolving a word means looking up all references to external
+ * words.
+ */
+ internal virtual void Resolve()
+ {
+ }
+
+ /*
+ * Execute this word. If the word is native, then its code is
+ * run right away; if the word is interpreted, then the entry
+ * sequence is executed.
+ */
+ internal virtual void Run(CPU cpu)
+ {
+ throw new Exception(String.Format(
+ "cannot run '{0}' at compile-time", Name));
+ }
+
+ /*
+ * All words may have an explicit C implementations. To be part
+ * of the generated C code, a word must either be interpreted,
+ * or have an explicit C implementation, or both.
+ */
+ internal string CCode {
+ get; set;
+ }
+
+ /*
+ * Get all words referenced from this one. This implies
+ * resolving the word.
+ */
+ internal virtual List<Word> GetReferences()
+ {
+ return new List<Word>();
+ }
+
+ /*
+ * Get all data blocks directly referenced from this one. This
+ * implies resolving the word.
+ */
+ internal virtual List<ConstData> GetDataBlocks()
+ {
+ return new List<ConstData>();
+ }
+
+ /*
+ * Produce the code elements for this word.
+ */
+ internal virtual void GenerateCodeElements(List<CodeElement> dst)
+ {
+ throw new Exception("Word does not yield code elements");
+ }
+
+ /*
+ * Compute/verify stack effect for this word.
+ */
+ internal virtual void AnalyseFlow()
+ {
+ }
+
+ /*
+ * Get maximum data stack usage for this word. This is the number
+ * of extra slots that this word may need on the data stack. If
+ * the stack effect is not known, this returns -1.
+ */
+ internal virtual int MaxDataStack {
+ get {
+ SType se = StackEffect;
+ if (!se.IsKnown) {
+ return -1;
+ }
+ if (se.NoExit) {
+ return 0;
+ } else {
+ return Math.Min(0, se.DataOut - se.DataIn);
+ }
+ }
+ }
+
+ /*
+ * Get maximum return stack usage for this word.
+ */
+ internal virtual int MaxReturnStack {
+ get {
+ return 0;
+ }
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+using System;
+using System.Collections.Generic;
+
+/*
+ * A WordBuilder instance organizes construction of a new interpreted word.
+ *
+ * Opcodes are accumulated with specific methods. A control-flow stack
+ * is maintained to resolve jumps.
+ *
+ * Each instance shall be used for only one word.
+ */
+
+class WordBuilder {
+
+ T0Comp TC;
+ string name;
+ int[] cfStack;
+ int cfPtr;
+ List<Opcode> code;
+ List<string> toResolve;
+ Dictionary<string, int> locals;
+ bool jumpToLast;
+
+ internal SType StackEffect {
+ get; set;
+ }
+
+ /*
+ * Create a new instance, with the specified word name.
+ */
+ internal WordBuilder(T0Comp TC, string name)
+ {
+ this.TC = TC;
+ this.name = name;
+ cfStack = new int[16];
+ cfPtr = -1;
+ code = new List<Opcode>();
+ toResolve = new List<string>();
+ locals = new Dictionary<string, int>();
+ jumpToLast = true;
+ StackEffect = SType.UNKNOWN;
+ }
+
+ /*
+ * Build the word. The control-flow stack must be empty. A 'ret'
+ * opcode is automatically appended if required.
+ */
+ internal Word Build()
+ {
+ if (cfPtr != -1) {
+ throw new Exception("control-flow stack is not empty");
+ }
+ if (jumpToLast || code[code.Count - 1].MayFallThrough) {
+ Ret();
+ }
+ Word w = new WordInterpreted(TC, name, locals.Count,
+ code.ToArray(), toResolve.ToArray());
+ w.StackEffect = StackEffect;
+ return w;
+ }
+
+ void Add(Opcode op)
+ {
+ Add(op, null);
+ }
+
+ void Add(Opcode op, string refName)
+ {
+ code.Add(op);
+ toResolve.Add(refName);
+ jumpToLast = false;
+ }
+
+ /*
+ * Rotate the control-flow stack at depth 'depth'.
+ */
+ internal void CSRoll(int depth)
+ {
+ int x = cfStack[cfPtr - depth];
+ Array.Copy(cfStack, cfPtr - (depth - 1),
+ cfStack, cfPtr - depth, depth);
+ cfStack[cfPtr] = x;
+ }
+
+ /*
+ * Make a copy of the control-flow element at depth 'depth', and
+ * push it on top of the control-flow stack.
+ */
+ internal void CSPick(int depth)
+ {
+ int x = cfStack[cfPtr - depth];
+ CSPush(x);
+ }
+
+ void CSPush(int x)
+ {
+ int len = cfStack.Length;
+ if (++ cfPtr == len) {
+ int[] ncf = new int[len << 1];
+ Array.Copy(cfStack, 0, ncf, 0, len);
+ cfStack = ncf;
+ }
+ cfStack[cfPtr] = x;
+ }
+
+ int CSPop()
+ {
+ return cfStack[cfPtr --];
+ }
+
+ /*
+ * Push an origin on the control-flow stack, corresponding to the
+ * next opcode to add.
+ */
+ internal void CSPushOrig()
+ {
+ CSPush(code.Count);
+ }
+
+ /*
+ * Push a destination on the control-flow stack, corresponding to
+ * the next opcode to add.
+ */
+ internal void CSPushDest()
+ {
+ CSPush(-code.Count - 1);
+ }
+
+ /*
+ * Pop an origin from the control-flow stack. An exception is
+ * thrown if the value is not an origin.
+ */
+ internal int CSPopOrig()
+ {
+ int x = CSPop();
+ if (x < 0) {
+ throw new Exception("not an origin");
+ }
+ return x;
+ }
+
+ /*
+ * Pop a destination from the control-flow stack. An exception is
+ * thrown if the value is not a destination.
+ */
+ internal int CSPopDest()
+ {
+ int x = CSPop();
+ if (x >= 0) {
+ throw new Exception("not a destination");
+ }
+ return -x - 1;
+ }
+
+ /*
+ * Add a "push literal" opcode.
+ */
+ internal void Literal(TValue v)
+ {
+ Add(new OpcodeConst(v));
+ }
+
+ /*
+ * Compile a "call" by name. This method implements the support
+ * for local variables:
+ *
+ * - If the target is '>' followed by a local variable name, then
+ * a "put local" opcode is added.
+ *
+ * - Otherwise, if the target is a local variable name, then a
+ * "get local" opcode is added.
+ *
+ * - Otherwise, a call to the named word is added. The target name
+ * will be resolved later on (typically, when the word containing
+ * the call opcode is first invoked, or when C code is generated).
+ */
+ internal void Call(string target)
+ {
+ string lname;
+ bool write;
+ if (target.StartsWith(">")) {
+ lname = target.Substring(1);
+ write = true;
+ } else {
+ lname = target;
+ write = false;
+ }
+ int lnum;
+ if (locals.TryGetValue(lname, out lnum)) {
+ if (write) {
+ Add(new OpcodePutLocal(lnum));
+ } else {
+ Add(new OpcodeGetLocal(lnum));
+ }
+ } else {
+ Add(new OpcodeCall(), target);
+ }
+ }
+
+ /*
+ * Add a "call" opcode to the designated word.
+ */
+ internal void CallExt(Word wtarget)
+ {
+ Add(new OpcodeCall(wtarget), null);
+ }
+
+ /*
+ * Add a "call" opcode to a word which is not currently resolved.
+ * This method ignores local variables.
+ */
+ internal void CallExt(string target)
+ {
+ Add(new OpcodeCall(), target);
+ }
+
+ /*
+ * Add a "get local" opcode; the provided local name must already
+ * be defined.
+ */
+ internal void GetLocal(string name)
+ {
+ int lnum;
+ if (locals.TryGetValue(name, out lnum)) {
+ Add(new OpcodeGetLocal(lnum));
+ } else {
+ throw new Exception("no such local: " + name);
+ }
+ }
+
+ /*
+ * Add a "put local" opcode; the provided local name must already
+ * be defined.
+ */
+ internal void PutLocal(string name)
+ {
+ int lnum;
+ if (locals.TryGetValue(name, out lnum)) {
+ Add(new OpcodePutLocal(lnum));
+ } else {
+ throw new Exception("no such local: " + name);
+ }
+ }
+
+ /*
+ * Define a new local name.
+ */
+ internal void DefLocal(string lname)
+ {
+ if (locals.ContainsKey(lname)) {
+ throw new Exception(String.Format(
+ "local already defined: {0}", lname));
+ }
+ locals[lname] = locals.Count;
+ }
+
+ /*
+ * Add a "call" opcode whose target is an XT value (which may be
+ * resolved or as yet unresolved).
+ */
+ internal void Call(TPointerXT xt)
+ {
+ if (xt.Target == null) {
+ Add(new OpcodeCall(), xt.Name);
+ } else {
+ Add(new OpcodeCall(xt.Target));
+ }
+ }
+
+ /*
+ * Add a "ret" opcode.
+ */
+ internal void Ret()
+ {
+ Add(new OpcodeRet());
+ }
+
+ /*
+ * Add a forward unconditional jump. The new opcode address is
+ * pushed on the control-flow stack as an origin.
+ */
+ internal void Ahead()
+ {
+ CSPushOrig();
+ Add(new OpcodeJumpUncond());
+ }
+
+ /*
+ * Add a forward conditional jump, which will be taken at runtime
+ * if the top-of-stack value is 'true'. The new opcode address is
+ * pushed on the control-flow stack as an origin.
+ */
+ internal void AheadIf()
+ {
+ CSPushOrig();
+ Add(new OpcodeJumpIf());
+ }
+
+ /*
+ * Add a forward conditional jump, which will be taken at runtime
+ * if the top-of-stack value is 'false'. The new opcode address is
+ * pushed on the control-flow stack as an origin.
+ */
+ internal void AheadIfNot()
+ {
+ CSPushOrig();
+ Add(new OpcodeJumpIfNot());
+ }
+
+ /*
+ * Resolve a previous forward jump to the current code address.
+ * The top of control-flow stack is popped and must be an origin.
+ */
+ internal void Then()
+ {
+ int x = CSPopOrig();
+ code[x].ResolveJump(code.Count - x - 1);
+ jumpToLast = true;
+ }
+
+ /*
+ * Push the current code address on the control-flow stack as a
+ * destination, to be used by an ulterior backward jump.
+ */
+ internal void Begin()
+ {
+ CSPushDest();
+ }
+
+ /*
+ * Add a backward unconditional jump. The jump target is popped
+ * from the control-flow stack as a destination.
+ */
+ internal void Again()
+ {
+ int x = CSPopDest();
+ Add(new OpcodeJumpUncond(x - code.Count - 1));
+ }
+
+ /*
+ * Add a backward conditional jump, which will be taken at runtime
+ * if the top-of-stack value is 'true'. The jump target is popped
+ * from the control-flow stack as a destination.
+ */
+ internal void AgainIf()
+ {
+ int x = CSPopDest();
+ Add(new OpcodeJumpIf(x - code.Count - 1));
+ }
+
+ /*
+ * Add a backward conditional jump, which will be taken at runtime
+ * if the top-of-stack value is 'false'. The jump target is popped
+ * from the control-flow stack as a destination.
+ */
+ internal void AgainIfNot()
+ {
+ int x = CSPopDest();
+ Add(new OpcodeJumpIfNot(x - code.Count - 1));
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+using System;
+using System.Collections.Generic;
+
+class WordData : Word {
+
+ ConstData blob;
+ string baseBlobName;
+ int offset;
+ bool ongoingResolution;
+
+ internal WordData(T0Comp owner, string name,
+ ConstData blob, int offset)
+ : base(owner, name)
+ {
+ this.blob = blob;
+ this.offset = offset;
+ StackEffect = new SType(0, 1);
+ }
+
+ internal WordData(T0Comp owner, string name,
+ string baseBlobName, int offset)
+ : base(owner, name)
+ {
+ this.baseBlobName = baseBlobName;
+ this.offset = offset;
+ StackEffect = new SType(0, 1);
+ }
+
+ internal override void Resolve()
+ {
+ if (blob != null) {
+ return;
+ }
+ if (ongoingResolution) {
+ throw new Exception(String.Format(
+ "circular reference in blobs ({0})", Name));
+ }
+ ongoingResolution = true;
+ WordData wd = TC.Lookup(baseBlobName) as WordData;
+ if (wd == null) {
+ throw new Exception(String.Format(
+ "data word '{0}' based on non-data word '{1}'",
+ Name, baseBlobName));
+ }
+ wd.Resolve();
+ blob = wd.blob;
+ offset += wd.offset;
+ ongoingResolution = false;
+ }
+
+ internal override void Run(CPU cpu)
+ {
+ Resolve();
+ cpu.Push(new TValue(offset, new TPointerBlob(blob)));
+ }
+
+ internal override List<ConstData> GetDataBlocks()
+ {
+ Resolve();
+ List<ConstData> r = new List<ConstData>();
+ r.Add(blob);
+ return r;
+ }
+
+ internal override void GenerateCodeElements(List<CodeElement> dst)
+ {
+ Resolve();
+ dst.Add(new CodeElementUInt(0));
+ dst.Add(new CodeElementUIntInt(1, blob.Address + offset));
+ dst.Add(new CodeElementUInt(0));
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+using System;
+using System.Collections.Generic;
+
+/*
+ * The implementation for interpreted words.
+ */
+
+class WordInterpreted : Word {
+
+ /*
+ * Get the number of local variables for this word.
+ */
+ internal int NumLocals {
+ get; private set;
+ }
+
+ /*
+ * Get the sequence of opcodes for this word.
+ */
+ internal Opcode[] Code {
+ get; private set;
+ }
+
+ string[] toResolve;
+
+ internal WordInterpreted(T0Comp owner, string name,
+ int numLocals, Opcode[] code, string[] toResolve)
+ : base(owner, name)
+ {
+ this.Code = code;
+ this.toResolve = toResolve;
+ NumLocals = numLocals;
+ }
+
+ internal override void Resolve()
+ {
+ if (toResolve == null) {
+ return;
+ }
+ for (int i = 0; i < toResolve.Length; i ++) {
+ string tt = toResolve[i];
+ if (tt == null) {
+ continue;
+ }
+ Code[i].ResolveTarget(TC.Lookup(tt));
+ }
+ toResolve = null;
+ }
+
+ internal override void Run(CPU cpu)
+ {
+ Resolve();
+ cpu.Enter(Code, NumLocals);
+ }
+
+ internal override List<Word> GetReferences()
+ {
+ Resolve();
+ List<Word> r = new List<Word>();
+ foreach (Opcode op in Code) {
+ Word w = op.GetReference(TC);
+ if (w != null) {
+ r.Add(w);
+ }
+ }
+ return r;
+ }
+
+ internal override List<ConstData> GetDataBlocks()
+ {
+ Resolve();
+ List<ConstData> r = new List<ConstData>();
+ foreach (Opcode op in Code) {
+ ConstData cd = op.GetDataBlock(TC);
+ if (cd != null) {
+ r.Add(cd);
+ }
+ }
+ return r;
+ }
+
+ internal override void GenerateCodeElements(List<CodeElement> dst)
+ {
+ Resolve();
+ int n = Code.Length;
+ CodeElement[] gcode = new CodeElement[n];
+ for (int i = 0; i < n; i ++) {
+ gcode[i] = Code[i].ToCodeElement();
+ }
+ for (int i = 0; i < n; i ++) {
+ Code[i].FixUp(gcode, i);
+ }
+ dst.Add(new CodeElementUInt((uint)NumLocals));
+ for (int i = 0; i < n; i ++) {
+ dst.Add(gcode[i]);
+ }
+ }
+
+ int flowAnalysis;
+ int maxDataStack;
+ int maxReturnStack;
+
+ bool MergeSA(int[] sa, int j, int c)
+ {
+ if (sa[j] == Int32.MinValue) {
+ sa[j] = c;
+ return true;
+ } else if (sa[j] != c) {
+ throw new Exception(string.Format(
+ "In word '{0}', offset {1}:"
+ + " stack action mismatch ({2} / {3})",
+ Name, j, sa[j], c));
+ } else {
+ return false;
+ }
+ }
+
+ internal override void AnalyseFlow()
+ {
+ switch (flowAnalysis) {
+ case 0:
+ break;
+ case 1:
+ return;
+ default:
+ throw new Exception("recursive call detected in '"
+ + Name + "'");
+ }
+ flowAnalysis = 2;
+ int n = Code.Length;
+ int[] sa = new int[n];
+ for (int i = 0; i < n; i ++) {
+ sa[i] = Int32.MinValue;
+ }
+ sa[0] = 0;
+ int[] toExplore = new int[n];
+ int tX = 0, tY = 0;
+ int off = 0;
+
+ int exitSA = Int32.MinValue;
+ int mds = 0;
+ int mrs = 0;
+
+ int maxDepth = 0;
+
+ for (;;) {
+ Opcode op = Code[off];
+ bool mft = op.MayFallThrough;
+ int c = sa[off];
+ int a;
+ if (op is OpcodeCall) {
+ Word w = op.GetReference(TC);
+ w.AnalyseFlow();
+ SType se = w.StackEffect;
+ if (!se.IsKnown) {
+ throw new Exception(string.Format(
+ "call from '{0}' to '{1}'"
+ + " with unknown stack effect",
+ Name, w.Name));
+ }
+ if (se.NoExit) {
+ mft = false;
+ a = 0;
+ } else {
+ a = se.DataOut - se.DataIn;
+ }
+ mds = Math.Max(mds, c + w.MaxDataStack);
+ mrs = Math.Max(mrs, w.MaxReturnStack);
+ maxDepth = Math.Min(maxDepth, c - se.DataIn);
+ } else if (op is OpcodeRet) {
+ if (exitSA == Int32.MinValue) {
+ exitSA = c;
+ } else if (exitSA != c) {
+ throw new Exception(string.Format(
+ "'{0}': exit stack action"
+ + " mismatch: {1} / {2}"
+ + " (offset {3})",
+ Name, exitSA, c, off));
+ }
+ a = 0;
+ } else {
+ a = op.StackAction;
+ mds = Math.Max(mds, c + a);
+ }
+ c += a;
+ maxDepth = Math.Min(maxDepth, c);
+
+ int j = op.JumpDisp;
+ if (j != 0) {
+ j += off + 1;
+ toExplore[tY ++] = j;
+ MergeSA(sa, j, c);
+ }
+ off ++;
+ if (!mft || !MergeSA(sa, off, c)) {
+ if (tX < tY) {
+ off = toExplore[tX ++];
+ } else {
+ break;
+ }
+ }
+ }
+
+ maxDataStack = mds;
+ maxReturnStack = 1 + NumLocals + mrs;
+
+ /*
+ * TODO: see about this warning. Usage of a 'fail'
+ * word (that does not exit) within a 'case..endcase'
+ * structure will make an unreachable opcode. In a future
+ * version we might want to automatically remove dead
+ * opcodes.
+ for (int i = 0; i < n; i ++) {
+ if (sa[i] == Int32.MinValue) {
+ Console.WriteLine("warning: word '{0}',"
+ + " offset {1}: unreachable opcode",
+ Name, i);
+ continue;
+ }
+ }
+ */
+
+ SType computed;
+ if (exitSA == Int32.MinValue) {
+ computed = new SType(-maxDepth, -1);
+ } else {
+ computed = new SType(-maxDepth, -maxDepth + exitSA);
+ }
+
+ if (StackEffect.IsKnown) {
+ if (!computed.IsSubOf(StackEffect)) {
+ throw new Exception(string.Format(
+ "word '{0}':"
+ + " computed stack effect {1}"
+ + " does not match declared {2}",
+ Name, computed.ToString(),
+ StackEffect.ToString()));
+ }
+ } else {
+ StackEffect = computed;
+ }
+
+ flowAnalysis = 1;
+ }
+
+ internal override int MaxDataStack {
+ get {
+ AnalyseFlow();
+ return maxDataStack;
+ }
+ }
+
+ internal override int MaxReturnStack {
+ get {
+ AnalyseFlow();
+ return maxReturnStack;
+ }
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+using System;
+using System.Collections.Generic;
+
+/*
+ * Class for native words.
+ */
+
+class WordNative : Word {
+
+ /*
+ * A type for the native implementation: a method that takes a
+ * CPU as parameter, and returns nothing.
+ */
+ internal delegate void NativeRun(CPU cpu);
+
+ NativeRun code;
+
+ internal WordNative(T0Comp owner, string name, NativeRun code)
+ : base(owner, name)
+ {
+ this.code = code;
+ }
+
+ internal WordNative(T0Comp owner, string name,
+ SType stackEffect, NativeRun code)
+ : this(owner, name, code)
+ {
+ StackEffect = stackEffect;
+ }
+
+ internal override void Run(CPU cpu)
+ {
+ code(cpu);
+ }
+}
--- /dev/null
+: \ `\n parse drop ; immediate
+
+\ This file defines the core non-native functions (mainly used for
+\ parsing words, i.e. not part of the generated output). The line above
+\ defines the syntax for comments.
+
+\ Define parenthesis comments.
+\ : ( `) parse drop ; immediate
+
+: else postpone ahead 1 cs-roll postpone then ; immediate
+: while postpone if 1 cs-roll ; immediate
+: repeat postpone again postpone then ; immediate
+
+: ['] ' ; immediate
+: [compile] compile ; immediate
+
+: 2drop drop drop ;
+: dup2 over over ;
+
+\ Local variables are defined with the native word '(local)'. We define
+\ a helper construction that mimics what is found in Apple's Open Firmware
+\ implementation. The syntax is: { a b ... ; c d ... }
+\ I.e. there is an opening brace, then some names. Names appearing before
+\ the semicolon are locals that are both defined and then filled with the
+\ values on stack (in stack order: { a b } fills 'b' with the top-of-stack,
+\ and 'a' with the value immediately below). Names appearing after the
+\ semicolon are not initialized.
+: __deflocal ( from_stack name -- )
+ dup (local) swap if
+ compile-local-write
+ else
+ drop
+ then ;
+: __deflocals ( from_stack -- )
+ next-word
+ dup "}" eqstr if
+ 2drop ret
+ then
+ dup ";" eqstr if
+ 2drop 0 __deflocals ret
+ then
+ over __deflocals
+ __deflocal ;
+: {
+ -1 __deflocals ; immediate
+
+\ Data building words.
+: data:
+ new-data-block next-word define-data-word ;
+: hexb|
+ 0 0 { acc z }
+ begin
+ char
+ dup `| = if
+ z if "Truncated hexadecimal byte" puts cr exitvm then
+ ret
+ then
+ dup 0x20 > if
+ hexval
+ z if acc 4 << + data-add8 else >acc then
+ z not >z
+ then
+ again ;
+
+\ Convert hexadecimal character to number. Complain loudly if conversion
+\ is not possible.
+: hexval ( char -- x )
+ hexval-nf dup 0 < if "Not an hex digit: " puts . cr exitvm then ;
+
+\ Convert hexadecimal character to number. If not an hexadecimal digit,
+\ return -1.
+: hexval-nf ( char -- x )
+ dup dup `0 >= swap `9 <= and if `0 - ret then
+ dup dup `A >= swap `F <= and if `A - 10 + ret then
+ dup dup `a >= swap `f <= and if `a - 10 + ret then
+ drop -1 ;
+
+\ Convert decimal character to number. Complain loudly if conversion
+\ is not possible.
+: decval ( char -- x )
+ decval-nf dup 0 < if "Not a decimal digit: " puts . cr exitvm then ;
+
+\ Convert decimal character to number. If not a decimal digit,
+\ return -1.
+: decval-nf ( char -- x )
+ dup dup `0 >= swap `9 <= and if `0 - ret then
+ drop -1 ;
+
+\ Commonly used shorthands.
+: 1+ 1 + ;
+: 2+ 2 + ;
+: 1- 1 - ;
+: 2- 2 - ;
+: 0= 0 = ;
+: 0<> 0 <> ;
+: 0< 0 < ;
+: 0> 0 > ;
+
+\ Get a 16-bit value from the constant data block. This uses big-endian
+\ encoding.
+: data-get16 ( addr -- x )
+ dup data-get8 8 << swap 1+ data-get8 + ;
+
+\ The case..endcase construction is the equivalent of 'switch' is C.
+\ Usage:
+\ case
+\ E1 of C1 endof
+\ E2 of C2 endof
+\ ...
+\ CN
+\ endcase
+\
+\ Upon entry, it considers the TOS (let's call it X). It will then evaluate
+\ E1, which should yield a single value Y1; at that point, the X value is
+\ still on the stack, just below Y1, and must remain untouched. The 'of'
+\ word compares X with Y1; if they are equal, C1 is executed, and then
+\ control jumps to after the 'endcase'. The X value is popped from the
+\ stack immediately before evaluating C1.
+\
+\ If X and Y1 are not equal, flow proceeds to E2, to obtain a value Y2 to
+\ compare with X. And so on.
+\
+\ If none of the 'of' clauses found a match, then CN is evaluated. When CN
+\ is evaluated, the X value is on the TOS, and CN must either leave it on
+\ the stack, or replace it with exactly one value; the 'endcase' word
+\ expects (and drops) one value.
+\
+\ Implementation: this is mostly copied from ANS Forth specification,
+\ although simplified a bit because we know that our control-flow stack
+\ is independent of the data stack. During compilation, the number of
+\ clauses is maintained on the stack; each of..endof clause really is
+\ an 'if..else' that must be terminated with a matching 'then' in 'endcase'.
+
+: case 0 ; immediate
+: of 1+ postpone over postpone = postpone if postpone drop ; immediate
+: endof postpone else ; immediate
+: endcase
+ postpone drop
+ begin dup while 1- postpone then repeat drop ; immediate
+
+\ A simpler and more generic "case": there is no management for a value
+\ on the stack, and each test is supposed to come up with its own boolean
+\ value.
+: choice 0 ; immediate
+: uf 1+ postpone if ; immediate
+: ufnot 1+ postpone ifnot ; immediate
+: enduf postpone else ; immediate
+: endchoice begin dup while 1- postpone then repeat drop ; immediate
+
+\ C implementations for native words that can be used in generated code.
+add-cc: co { T0_CO(); }
+add-cc: execute { T0_ENTER(ip, rp, T0_POP()); }
+add-cc: drop { (void)T0_POP(); }
+add-cc: dup { T0_PUSH(T0_PEEK(0)); }
+add-cc: swap { T0_SWAP(); }
+add-cc: over { T0_PUSH(T0_PEEK(1)); }
+add-cc: rot { T0_ROT(); }
+add-cc: -rot { T0_NROT(); }
+add-cc: roll { T0_ROLL(T0_POP()); }
+add-cc: pick { T0_PICK(T0_POP()); }
+add-cc: + {
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a + b);
+}
+add-cc: - {
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a - b);
+}
+add-cc: neg {
+ uint32_t a = T0_POP();
+ T0_PUSH(-a);
+}
+add-cc: * {
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a * b);
+}
+add-cc: / {
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSHi(a / b);
+}
+add-cc: u/ {
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a / b);
+}
+add-cc: % {
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSHi(a % b);
+}
+add-cc: u% {
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a % b);
+}
+add-cc: < {
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a < b));
+}
+add-cc: <= {
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a <= b));
+}
+add-cc: > {
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a > b));
+}
+add-cc: >= {
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a >= b));
+}
+add-cc: = {
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(-(uint32_t)(a == b));
+}
+add-cc: <> {
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(-(uint32_t)(a != b));
+}
+add-cc: u< {
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(-(uint32_t)(a < b));
+}
+add-cc: u<= {
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(-(uint32_t)(a <= b));
+}
+add-cc: u> {
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(-(uint32_t)(a > b));
+}
+add-cc: u>= {
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(-(uint32_t)(a >= b));
+}
+add-cc: and {
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a & b);
+}
+add-cc: or {
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a | b);
+}
+add-cc: xor {
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a ^ b);
+}
+add-cc: not {
+ uint32_t a = T0_POP();
+ T0_PUSH(~a);
+}
+add-cc: << {
+ int c = (int)T0_POPi();
+ uint32_t x = T0_POP();
+ T0_PUSH(x << c);
+}
+add-cc: >> {
+ int c = (int)T0_POPi();
+ int32_t x = T0_POPi();
+ T0_PUSHi(x >> c);
+}
+add-cc: u>> {
+ int c = (int)T0_POPi();
+ uint32_t x = T0_POP();
+ T0_PUSH(x >> c);
+}
+add-cc: data-get8 {
+ size_t addr = T0_POP();
+ T0_PUSH(t0_datablock[addr]);
+}
+
+add-cc: . {
+ extern int printf(const char *fmt, ...);
+ printf(" %ld", (long)T0_POPi());
+}
+add-cc: putc {
+ extern int printf(const char *fmt, ...);
+ printf("%c", (char)T0_POPi());
+}
+add-cc: puts {
+ extern int printf(const char *fmt, ...);
+ printf("%s", &t0_datablock[T0_POPi()]);
+}
+add-cc: cr {
+ extern int printf(const char *fmt, ...);
+ printf("\n");
+}
+add-cc: eqstr {
+ const void *b = &t0_datablock[T0_POPi()];
+ const void *a = &t0_datablock[T0_POPi()];
+ T0_PUSH(-(int32_t)(strcmp(a, b) == 0));
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+#ifndef BR_BEARSSL_H__
+#define BR_BEARSSL_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "bearssl_hash.h"
+#include "bearssl_hmac.h"
+#include "bearssl_rand.h"
+#include "bearssl_prf.h"
+#include "bearssl_block.h"
+#include "bearssl_rsa.h"
+#include "bearssl_ec.h"
+#include "bearssl_ssl.h"
+#include "bearssl_x509.h"
+#include "bearssl_pem.h"
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+#ifndef BR_BEARSSL_BLOCK_H__
+#define BR_BEARSSL_BLOCK_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+/*
+ * Block Ciphers
+ * -------------
+ *
+ * For a block cipher implementation, up to three separate sets of
+ * functions are provided, for CBC encryption, CBC decryption, and CTR
+ * encryption/decryption. Each set has its own context structure,
+ * initialized with the encryption key. Each set of functions is
+ * provided both as named functions, and through an OOP interface.
+ *
+ * For CBC encryption and decryption, the data to encrypt or decrypt is
+ * referenced as a sequence of blocks. The implementations assume that
+ * there is no partial block; no padding is applied or removed. The
+ * caller is responsible for handling any kind of padding.
+ *
+ * Function for CTR encryption are defined only for block ciphers with
+ * blocks of 16 bytes or more (i.e. AES, but not DES/3DES).
+ *
+ * Each implemented block cipher is identified by an "internal name"
+ * from which are derived the names of structures and functions that
+ * implement the cipher. For the block cipher of internal name "xxx",
+ * the following are defined:
+ *
+ * br_xxx_BLOCK_SIZE
+ * A macro that evaluates to the block size (in bytes) of the
+ * cipher. For all implemented block ciphers, this value is a
+ * power of two.
+ *
+ * br_xxx_cbcenc_keys
+ * Context structure that contains the subkeys resulting from the key
+ * expansion. These subkeys are appropriate for CBC encryption. The
+ * structure first field is called 'vtable' and points to the
+ * appropriate OOP structure.
+ *
+ * br_xxx_cbcenc_init(br_xxx_cbcenc_keys *ctx, const void *key, size_t len)
+ * Perform key expansion: subkeys for CBC encryption are computed and
+ * written in the provided context structure. The key length MUST be
+ * adequate for the implemented block cipher. This function also sets
+ * the 'vtable' field.
+ *
+ * br_xxx_cbcenc_run(const br_xxx_cbcenc_keys *ctx,
+ * void *iv, void *data, size_t len)
+ * Perform CBC encryption of 'len' bytes, in place. The encrypted data
+ * replaces the cleartext. 'len' MUST be a multiple of the block length
+ * (if it is not, the function may loop forever or overflow a buffer).
+ * The IV is provided with the 'iv' pointer; it is also updated with
+ * a copy of the last encrypted block.
+ *
+ * br_xxx_cbcdec_keys
+ * Context structure that contains the subkeys resulting from the key
+ * expansion. These subkeys are appropriate for CBC decryption. The
+ * structure first field is called 'vtable' and points to the
+ * appropriate OOP structure.
+ *
+ * br_xxx_cbcdec_init(br_xxx_cbcenc_keys *ctx, const void *key, size_t len)
+ * Perform key expansion: subkeys for CBC decryption are computed and
+ * written in the provided context structure. The key length MUST be
+ * adequate for the implemented block cipher. This function also sets
+ * the 'vtable' field.
+ *
+ * br_xxx_cbcdec_run(const br_xxx_cbcdec_keys *ctx,
+ * void *iv, void *data, size_t num_blocks)
+ * Perform CBC decryption of 'len' bytes, in place. The decrypted data
+ * replaces the ciphertext. 'len' MUST be a multiple of the block length
+ * (if it is not, the function may loop forever or overflow a buffer).
+ * The IV is provided with the 'iv' pointer; it is also updated with
+ * a copy of the last encrypted block.
+ *
+ * br_xxx_ctr_keys
+ * Context structure that contains the subkeys resulting from the key
+ * expansion. These subkeys are appropriate for CTR encryption and
+ * decryption. The structure first field is called 'vtable' and
+ * points to the appropriate OOP structure.
+ *
+ * br_xxx_ctr_init(br_xxx_ctr_keys *ctx, const void *key, size_t len)
+ * Perform key expansion: subkeys for CTR encryption and decryption
+ * are computed and written in the provided context structure. The
+ * key length MUST be adequate for the implemented block cipher. This
+ * function also sets the 'vtable' field.
+ *
+ * br_xxx_ctr_run(const br_xxx_ctr_keys *ctx, const void *iv,
+ * uint32_t cc, void *data, size_t len) [returns uint32_t]
+ * Perform CTR encryption/decryption of some data. Processing is done
+ * "in place" (the output data replaces the input data). This function
+ * implements the "standard incrementing function" from NIST SP800-38A,
+ * annex B: the IV length shall be 4 bytes less than the block size
+ * (i.e. 12 bytes for AES) and the counter is the 32-bit value starting
+ * with 'cc'. The data length ('len') is not necessarily a multiple of
+ * the block size. The new counter value is returned, which supports
+ * chunked processing, provided that each chunk length (except possibly
+ * the last one) is a multiple of the block size.
+ *
+ *
+ * It shall be noted that the key expansion functions return 'void'. If
+ * the provided key length is not allowed, then there will be no error
+ * reporting; implementations need not validate the key length, thus an
+ * invalid key length may result in undefined behaviour (e.g. buffer
+ * overflow).
+ *
+ * Subkey structures contain no interior pointer, and no external
+ * resources are allocated upon key expansion. They can thus be
+ * discarded without any explicit deallocation.
+ *
+ *
+ * Object-oriented API: each context structure begins with a field
+ * (called 'vtable') that points to an instance of a structure that
+ * references the relevant functions through pointers. Each such
+ * structure contains the following:
+ *
+ * context_size size (in bytes) of the context structure for subkeys
+ * block_size cipher block size (in bytes)
+ * log_block_size base-2 logarithm of cipher block size
+ * init pointer to the key expansion function
+ * run pointer to the encryption/decryption function
+ *
+ * Static, constant instances of these structures are defined, under
+ * the names:
+ *
+ * br_xxx_cbcenc_vtable
+ * br_xxx_cbcdec_vtable
+ * br_xxx_ctr_vtable
+ *
+ *
+ * Implemented Block Ciphers
+ * -------------------------
+ *
+ * Function Name Allowed key lengths (bytes)
+ *
+ * AES aes_ct 16, 24 and 32
+ * AES aes_ct64 16, 24 and 32
+ * AES aes_big 16, 24 and 32
+ * AES aes_small 16, 24 and 32
+ * DES des_ct 8, 16 and 24
+ * DES des_tab 8, 16 and 24
+ *
+ * 'aes_big' is a "classical" AES implementation, using tables. It
+ * is fast but not constant-time, since it makes data-dependent array
+ * accesses.
+ *
+ * 'aes_small' is an AES implementation optimized for code size. It
+ * is substantially slower than 'aes_big'; it is not constant-time
+ * either.
+ *
+ * 'aes_ct' is a constant-time implementation of AES; its code is about
+ * as big as that of 'aes_big', while its performance is comparable to
+ * that of 'aes_small'. However, it is constant-time. This
+ * implementation should thus be considered to be the "default" AES in
+ * BearSSL, to be used unless the operational context guarantees that a
+ * non-constant-time implementation is safe, or an architecture-specific
+ * constant-time implementation can be used (e.g. using dedicated
+ * hardware opcodes).
+ *
+ * 'aes_ct64' is another constant-time implementation of AES. It is
+ * similar to 'aes_ct' but uses 64-bit values, for faster processing
+ * on 64-bit machines.
+ *
+ * 'des_tab' is a classic, table-based implementation of DES/3DES. It
+ * is not constant-time.
+ *
+ * 'des_ct' is an constant-time implementation of DES/3DES. It is
+ * substantially slower than 'des_tab'.
+ */
+
+typedef struct br_block_cbcenc_class_ br_block_cbcenc_class;
+struct br_block_cbcenc_class_ {
+ size_t context_size;
+ unsigned block_size;
+ unsigned log_block_size;
+ void (*init)(const br_block_cbcenc_class **ctx,
+ const void *key, size_t key_len);
+ void (*run)(const br_block_cbcenc_class *const *ctx,
+ void *iv, void *data, size_t len);
+};
+
+typedef struct br_block_cbcdec_class_ br_block_cbcdec_class;
+struct br_block_cbcdec_class_ {
+ size_t context_size;
+ unsigned block_size;
+ unsigned log_block_size;
+ void (*init)(const br_block_cbcdec_class **ctx,
+ const void *key, size_t key_len);
+ void (*run)(const br_block_cbcdec_class *const *ctx,
+ void *iv, void *data, size_t len);
+};
+
+typedef struct br_block_ctr_class_ br_block_ctr_class;
+struct br_block_ctr_class_ {
+ size_t context_size;
+ unsigned block_size;
+ unsigned log_block_size;
+ void (*init)(const br_block_ctr_class **ctx,
+ const void *key, size_t key_len);
+ uint32_t (*run)(const br_block_ctr_class *const *ctx,
+ const void *iv, uint32_t cc, void *data, size_t len);
+};
+
+/*
+ * Traditional, table-based AES implementation. It is fast, but uses
+ * internal tables (in particular a 1 kB table for encryption, another
+ * 1 kB table for decryption, and a 256-byte table for key schedule),
+ * and it is not constant-time. In contexts where cache-timing attacks
+ * apply, this implementation may leak the secret key.
+ */
+#define br_aes_big_BLOCK_SIZE 16
+typedef struct {
+ const br_block_cbcenc_class *vtable;
+ uint32_t skey[60];
+ unsigned num_rounds;
+} br_aes_big_cbcenc_keys;
+typedef struct {
+ const br_block_cbcdec_class *vtable;
+ uint32_t skey[60];
+ unsigned num_rounds;
+} br_aes_big_cbcdec_keys;
+typedef struct {
+ const br_block_ctr_class *vtable;
+ uint32_t skey[60];
+ unsigned num_rounds;
+} br_aes_big_ctr_keys;
+extern const br_block_cbcenc_class br_aes_big_cbcenc_vtable;
+extern const br_block_cbcdec_class br_aes_big_cbcdec_vtable;
+extern const br_block_ctr_class br_aes_big_ctr_vtable;
+void br_aes_big_cbcenc_init(br_aes_big_cbcenc_keys *ctx,
+ const void *key, size_t len);
+void br_aes_big_cbcdec_init(br_aes_big_cbcdec_keys *ctx,
+ const void *key, size_t len);
+void br_aes_big_ctr_init(br_aes_big_ctr_keys *ctx,
+ const void *key, size_t len);
+void br_aes_big_cbcenc_run(const br_aes_big_cbcenc_keys *ctx, void *iv,
+ void *data, size_t len);
+void br_aes_big_cbcdec_run(const br_aes_big_cbcdec_keys *ctx, void *iv,
+ void *data, size_t len);
+uint32_t br_aes_big_ctr_run(const br_aes_big_ctr_keys *ctx,
+ const void *iv, uint32_t cc, void *data, size_t len);
+
+/*
+ * AES implementation optimized for size. It is slower than the
+ * traditional table-based AES implementation, but requires much less
+ * code. It still uses data-dependent table accesses (albeit within a
+ * much smaller 256-byte table), which makes it conceptually vulnerable
+ * to cache-timing attacks.
+ */
+#define br_aes_small_BLOCK_SIZE 16
+typedef struct {
+ const br_block_cbcenc_class *vtable;
+ uint32_t skey[60];
+ unsigned num_rounds;
+} br_aes_small_cbcenc_keys;
+typedef struct {
+ const br_block_cbcdec_class *vtable;
+ uint32_t skey[60];
+ unsigned num_rounds;
+} br_aes_small_cbcdec_keys;
+typedef struct {
+ const br_block_ctr_class *vtable;
+ uint32_t skey[60];
+ unsigned num_rounds;
+} br_aes_small_ctr_keys;
+extern const br_block_cbcenc_class br_aes_small_cbcenc_vtable;
+extern const br_block_cbcdec_class br_aes_small_cbcdec_vtable;
+extern const br_block_ctr_class br_aes_small_ctr_vtable;
+void br_aes_small_cbcenc_init(br_aes_small_cbcenc_keys *ctx,
+ const void *key, size_t len);
+void br_aes_small_cbcdec_init(br_aes_small_cbcdec_keys *ctx,
+ const void *key, size_t len);
+void br_aes_small_ctr_init(br_aes_small_ctr_keys *ctx,
+ const void *key, size_t len);
+void br_aes_small_cbcenc_run(const br_aes_small_cbcenc_keys *ctx, void *iv,
+ void *data, size_t len);
+void br_aes_small_cbcdec_run(const br_aes_small_cbcdec_keys *ctx, void *iv,
+ void *data, size_t len);
+uint32_t br_aes_small_ctr_run(const br_aes_small_ctr_keys *ctx,
+ const void *iv, uint32_t cc, void *data, size_t len);
+
+/*
+ * Constant-time AES implementation. Its size is similar to that of
+ * 'aes_big', and its performance is similar to that of 'aes_small' (faster
+ * decryption, slower encryption). However, it is constant-time, i.e.
+ * immune to cache-timing and similar attacks.
+ */
+#define br_aes_ct_BLOCK_SIZE 16
+typedef struct {
+ const br_block_cbcenc_class *vtable;
+ uint32_t skey[60];
+ unsigned num_rounds;
+} br_aes_ct_cbcenc_keys;
+typedef struct {
+ const br_block_cbcdec_class *vtable;
+ uint32_t skey[60];
+ unsigned num_rounds;
+} br_aes_ct_cbcdec_keys;
+typedef struct {
+ const br_block_ctr_class *vtable;
+ uint32_t skey[60];
+ unsigned num_rounds;
+} br_aes_ct_ctr_keys;
+extern const br_block_cbcenc_class br_aes_ct_cbcenc_vtable;
+extern const br_block_cbcdec_class br_aes_ct_cbcdec_vtable;
+extern const br_block_ctr_class br_aes_ct_ctr_vtable;
+void br_aes_ct_cbcenc_init(br_aes_ct_cbcenc_keys *ctx,
+ const void *key, size_t len);
+void br_aes_ct_cbcdec_init(br_aes_ct_cbcdec_keys *ctx,
+ const void *key, size_t len);
+void br_aes_ct_ctr_init(br_aes_ct_ctr_keys *ctx,
+ const void *key, size_t len);
+void br_aes_ct_cbcenc_run(const br_aes_ct_cbcenc_keys *ctx, void *iv,
+ void *data, size_t len);
+void br_aes_ct_cbcdec_run(const br_aes_ct_cbcdec_keys *ctx, void *iv,
+ void *data, size_t len);
+uint32_t br_aes_ct_ctr_run(const br_aes_ct_ctr_keys *ctx,
+ const void *iv, uint32_t cc, void *data, size_t len);
+
+/*
+ * 64-bit constant-time AES implementation. It is similar to 'aes_ct'
+ * but uses 64-bit registers, making it about twice faster than 'aes_ct'
+ * on 64-bit platforms, while remaining constant-time and with a similar
+ * code size. (The doubling in performance is only for CBC decryption
+ * and CTR mode; CBC encryption is non-parallel and cannot benefit from
+ * the larger registers.)
+ */
+#define br_aes_ct64_BLOCK_SIZE 16
+typedef struct {
+ const br_block_cbcenc_class *vtable;
+ uint64_t skey[30];
+ unsigned num_rounds;
+} br_aes_ct64_cbcenc_keys;
+typedef struct {
+ const br_block_cbcdec_class *vtable;
+ uint64_t skey[30];
+ unsigned num_rounds;
+} br_aes_ct64_cbcdec_keys;
+typedef struct {
+ const br_block_ctr_class *vtable;
+ uint64_t skey[30];
+ unsigned num_rounds;
+} br_aes_ct64_ctr_keys;
+extern const br_block_cbcenc_class br_aes_ct64_cbcenc_vtable;
+extern const br_block_cbcdec_class br_aes_ct64_cbcdec_vtable;
+extern const br_block_ctr_class br_aes_ct64_ctr_vtable;
+void br_aes_ct64_cbcenc_init(br_aes_ct64_cbcenc_keys *ctx,
+ const void *key, size_t len);
+void br_aes_ct64_cbcdec_init(br_aes_ct64_cbcdec_keys *ctx,
+ const void *key, size_t len);
+void br_aes_ct64_ctr_init(br_aes_ct64_ctr_keys *ctx,
+ const void *key, size_t len);
+void br_aes_ct64_cbcenc_run(const br_aes_ct64_cbcenc_keys *ctx, void *iv,
+ void *data, size_t len);
+void br_aes_ct64_cbcdec_run(const br_aes_ct64_cbcdec_keys *ctx, void *iv,
+ void *data, size_t len);
+uint32_t br_aes_ct64_ctr_run(const br_aes_ct64_ctr_keys *ctx,
+ const void *iv, uint32_t cc, void *data, size_t len);
+
+/*
+ * These structures are large enough to accommodate subkeys for all
+ * AES implementations.
+ */
+typedef union {
+ const br_block_cbcenc_class *vtable;
+ br_aes_big_cbcenc_keys big;
+ br_aes_small_cbcenc_keys small;
+ br_aes_ct_cbcenc_keys ct;
+ br_aes_ct64_cbcenc_keys ct64;
+} br_aes_gen_cbcenc_keys;
+typedef union {
+ const br_block_cbcdec_class *vtable;
+ br_aes_big_cbcdec_keys big;
+ br_aes_small_cbcdec_keys small;
+ br_aes_ct_cbcdec_keys ct;
+ br_aes_ct64_cbcdec_keys ct64;
+} br_aes_gen_cbcdec_keys;
+typedef union {
+ const br_block_ctr_class *vtable;
+ br_aes_big_ctr_keys big;
+ br_aes_small_ctr_keys small;
+ br_aes_ct_ctr_keys ct;
+ br_aes_ct64_ctr_keys ct64;
+} br_aes_gen_ctr_keys;
+
+/*
+ * Traditional, table-based implementation for DES/3DES. Since tables are
+ * used, cache-timing attacks are conceptually possible.
+ */
+#define br_des_tab_BLOCK_SIZE 8
+typedef struct {
+ const br_block_cbcenc_class *vtable;
+ uint32_t skey[96];
+ unsigned num_rounds;
+} br_des_tab_cbcenc_keys;
+typedef struct {
+ const br_block_cbcdec_class *vtable;
+ uint32_t skey[96];
+ unsigned num_rounds;
+} br_des_tab_cbcdec_keys;
+extern const br_block_cbcenc_class br_des_tab_cbcenc_vtable;
+extern const br_block_cbcdec_class br_des_tab_cbcdec_vtable;
+void br_des_tab_cbcenc_init(br_des_tab_cbcenc_keys *ctx,
+ const void *key, size_t len);
+void br_des_tab_cbcdec_init(br_des_tab_cbcdec_keys *ctx,
+ const void *key, size_t len);
+void br_des_tab_cbcenc_run(const br_des_tab_cbcenc_keys *ctx, void *iv,
+ void *data, size_t len);
+void br_des_tab_cbcdec_run(const br_des_tab_cbcdec_keys *ctx, void *iv,
+ void *data, size_t len);
+
+/*
+ * Constant-time implementation for DES/3DES. It is substantially slower
+ * (by a factor of about 4x), but also immune to cache-timing attacks.
+ */
+#define br_des_ct_BLOCK_SIZE 8
+typedef struct {
+ const br_block_cbcenc_class *vtable;
+ uint32_t skey[96];
+ unsigned num_rounds;
+} br_des_ct_cbcenc_keys;
+typedef struct {
+ const br_block_cbcdec_class *vtable;
+ uint32_t skey[96];
+ unsigned num_rounds;
+} br_des_ct_cbcdec_keys;
+extern const br_block_cbcenc_class br_des_ct_cbcenc_vtable;
+extern const br_block_cbcdec_class br_des_ct_cbcdec_vtable;
+void br_des_ct_cbcenc_init(br_des_ct_cbcenc_keys *ctx,
+ const void *key, size_t len);
+void br_des_ct_cbcdec_init(br_des_ct_cbcdec_keys *ctx,
+ const void *key, size_t len);
+void br_des_ct_cbcenc_run(const br_des_ct_cbcenc_keys *ctx, void *iv,
+ void *data, size_t len);
+void br_des_ct_cbcdec_run(const br_des_ct_cbcdec_keys *ctx, void *iv,
+ void *data, size_t len);
+
+/*
+ * These structures are large enough to accommodate subkeys for all
+ * DES/3DES implementations.
+ */
+typedef union {
+ const br_block_cbcenc_class *vtable;
+ br_des_tab_cbcenc_keys tab;
+ br_des_ct_cbcenc_keys ct;
+} br_des_gen_cbcenc_keys;
+typedef union {
+ const br_block_cbcdec_class *vtable;
+ br_des_tab_cbcdec_keys tab;
+ br_des_ct_cbcdec_keys ct;
+} br_des_gen_cbcdec_keys;
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+#ifndef BR_BEARSSL_EC_H__
+#define BR_BEARSSL_EC_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+/*
+ * Elliptic Curves
+ * ---------------
+ *
+ * ECDSA signatures have two standard formats, called "raw" and "asn1".
+ * Internally, such a signature is a pair of modular integers (r,s).
+ * The "raw" format is the concatenation of the unsigned big-endian
+ * encodings of these two integers, possibly left-padded with zeros so
+ * that they have the same encoded length. The "asn1" format is the
+ * DER encoding of an ASN.1 structure that contains the two integer
+ * values:
+ *
+ * ECDSASignature ::= SEQUENCE {
+ * r INTEGER,
+ * s INTEGER
+ * }
+ *
+ * Low-level implementations defined here work on the "raw" format.
+ * Conversion functions are provided.
+ *
+ * Note that for a given signature, the "raw" format is not fully
+ * deterministic, in that it does not enforce a minimal common length.
+ * The functions below MUST ensure, when producing signatures, that
+ * the signature length never exceeds 2*qlen, where qlen is the length,
+ * in bytes, of the minimal unsigned big-endian encoding of the curve
+ * subgroup order.
+ *
+ * Conversion of a "raw" format signature into "asn1" may enlarge a
+ * signature by no more than 9 bytes for all supported curves.
+ */
+
+/*
+ * Standard curve ID. These ID are equal to the assigned numerical
+ * identifiers assigned to these curves for TLS:
+ * http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8
+ */
+#define BR_EC_sect163k1 1
+#define BR_EC_sect163r1 2
+#define BR_EC_sect163r2 3
+#define BR_EC_sect193r1 4
+#define BR_EC_sect193r2 5
+#define BR_EC_sect233k1 6
+#define BR_EC_sect233r1 7
+#define BR_EC_sect239k1 8
+#define BR_EC_sect283k1 9
+#define BR_EC_sect283r1 10
+#define BR_EC_sect409k1 11
+#define BR_EC_sect409r1 12
+#define BR_EC_sect571k1 13
+#define BR_EC_sect571r1 14
+#define BR_EC_secp160k1 15
+#define BR_EC_secp160r1 16
+#define BR_EC_secp160r2 17
+#define BR_EC_secp192k1 18
+#define BR_EC_secp192r1 19
+#define BR_EC_secp224k1 20
+#define BR_EC_secp224r1 21
+#define BR_EC_secp256k1 22
+#define BR_EC_secp256r1 23
+#define BR_EC_secp384r1 24
+#define BR_EC_secp521r1 25
+#define BR_EC_brainpoolP256r1 26
+#define BR_EC_brainpoolP384r1 27
+#define BR_EC_brainpoolP512r1 28
+
+/*
+ * Structure for an EC public key.
+ */
+typedef struct {
+ int curve;
+ unsigned char *q;
+ size_t qlen;
+} br_ec_public_key;
+
+/*
+ * Structure for an EC private key.
+ */
+typedef struct {
+ int curve;
+ unsigned char *x;
+ size_t xlen;
+} br_ec_private_key;
+
+/*
+ * Type for an EC implementation.
+ *
+ * supported_curves
+ * Bit mask for supported curves: if curve 'id' is supported, then
+ * bit '1 << id' is set.
+ *
+ * generator
+ * Get a pointer to the conventional generator for a given curve.
+ *
+ * order
+ * Get a pointer to the curve order (minimal unsigned big-endian
+ * encoding).
+ *
+ * mul
+ * Compute x*G. Provided point G (encoded size Glen) must be valid and
+ * distinct from the point at infinity. 'x' must be non-zero and less
+ * than the curve order. On error, 0 is returned; an invalid G (or
+ * point at infinity) is always detected, as well as a case of x = 0.
+ * However, if x is a non-zero multiple of the curve order, then it is
+ * not guaranteed that an error is reported.
+ *
+ * muladd
+ * compute x*A+y*B, result being written over A. Points and multipliers
+ * must fulfill the same conditions as for mul().
+ */
+typedef struct {
+ uint32_t supported_curves;
+ const unsigned char *(*generator)(int curve, size_t *len);
+ const unsigned char *(*order)(int curve, size_t *len);
+ uint32_t (*mul)(unsigned char *G, size_t Glen,
+ const unsigned char *x, size_t xlen, int curve);
+ uint32_t (*muladd)(unsigned char *A, const unsigned char *B, size_t len,
+ const unsigned char *x, size_t xlen,
+ const unsigned char *y, size_t ylen, int curve);
+} br_ec_impl;
+
+/*
+ * The 'i31' implementation for elliptic curves. It supports secp256r1,
+ * secp384r1 and secp521r1 (aka NIST curves P-256, P-384 and P-521).
+ */
+extern const br_ec_impl br_ec_prime_i31;
+
+/*
+ * Convert a signature from "raw" to "asn1". Conversion is done "in
+ * place" and the new length is returned. Conversion may enlarge the
+ * signature, but by no more than 9 bytes at most. On error, 0 is
+ * returned (error conditions include an odd raw signature length, or an
+ * oversized integer).
+ */
+size_t br_ecdsa_raw_to_asn1(void *sig, size_t sig_len);
+
+/*
+ * Convert a signature from "asn1" to "raw". Conversion is done "in
+ * place" and the new length is returned. Conversion in that direction
+ * always reduced signature length. On error, 0 is returned (error
+ * conditions include an invalid signature format or an oversized
+ * integer).
+ */
+size_t br_ecdsa_asn1_to_raw(void *sig, size_t sig_len);
+
+/*
+ * Type for an ECDSA signer function. A pointer to the EC implementation
+ * is provided. The hash value is assumed to have the length inferred
+ * from the designated hash function class.
+ *
+ * Signature is written in the buffer pointed to by 'sig', and the length
+ * (in bytes) is returned. On error, nothing is written in the buffer,
+ * and 0 is returned.
+ *
+ * The signature format is either "raw" or "asn1", depending on the
+ * implementation; maximum length is predictable from the implemented
+ * curve:
+ *
+ * curve raw asn1
+ * NIST P-256 64 72
+ * NIST P-384 96 104
+ * NIST P-521 132 139
+ */
+typedef size_t (*br_ecdsa_sign)(const br_ec_impl *impl,
+ const br_hash_class *hf, const void *hash_value,
+ const br_ec_private_key *sk, void *sig);
+
+/*
+ * Verify ECDSA signature. Returned value is 1 on success, 0 on error.
+ */
+typedef uint32_t (*br_ecdsa_vrfy)(const br_ec_impl *impl,
+ const void *hash, size_t hash_len,
+ const br_ec_public_key *pk, const void *sig, size_t sig_len);
+
+/*
+ * ECDSA implementation using the "i31" integers.
+ */
+size_t br_ecdsa_i31_sign_asn1(const br_ec_impl *impl,
+ const br_hash_class *hf, const void *hash_value,
+ const br_ec_private_key *sk, void *sig);
+size_t br_ecdsa_i31_sign_raw(const br_ec_impl *impl,
+ const br_hash_class *hf, const void *hash_value,
+ const br_ec_private_key *sk, void *sig);
+uint32_t br_ecdsa_i31_vrfy_asn1(const br_ec_impl *impl,
+ const void *hash, size_t hash_len,
+ const br_ec_public_key *pk, const void *sig, size_t sig_len);
+uint32_t br_ecdsa_i31_vrfy_raw(const br_ec_impl *impl,
+ const void *hash, size_t hash_len,
+ const br_ec_public_key *pk, const void *sig, size_t sig_len);
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+#ifndef BR_BEARSSL_HASH_H__
+#define BR_BEARSSL_HASH_H__
+
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+/*
+ * Hash Functions
+ * --------------
+ *
+ * For hash function 'xxx', the following elements are defined:
+ *
+ * br_xxx_vtable
+ * An externally defined instance of br_hash_class.
+ *
+ * br_xxx_SIZE
+ * A macro that evaluates to the output size (in bytes) of the
+ * hash function.
+ *
+ * br_xxx_ID
+ * A macro that evaluates to a symbolic identifier for the hash
+ * function. Such identifiers are used with HMAC and signature
+ * algorithm implementations.
+ * NOTE: the numerical value of these identifiers MUST match the
+ * constants for hash function identification in TLS 1.2 (see RFC
+ * 5246, section 7.4.1.4.1). These are values 1 to 6, for MD5,
+ * SHA-1, SHA-224, SHA-256, SHA-384 and SHA-512, respectively.
+ *
+ * br_xxx_context
+ * Context for an ongoing computation. It is allocated by the
+ * caller, and a pointer to it is passed to all functions. A
+ * context contains no interior pointer, so it can be moved around
+ * and cloned (with a simple memcpy() or equivalent) in order to
+ * capture the function state at some point. Computations that use
+ * distinct context structures are independent of each other. The
+ * first field of br_xxx_context is always a pointer to the
+ * br_xxx_vtable structure; br_xxx_init() sets that pointer.
+ *
+ * br_xxx_init(br_xxx_context *ctx)
+ * Initialize the provided context. Previous contents of the structure
+ * are ignored. This calls resets the context to the start of a new
+ * hash computation.
+ *
+ * br_xxx_update(br_xxx_context *ctx, const void *data, size_t len)
+ * Add some more bytes to the hash computation represented by the
+ * provided context.
+ *
+ * br_xxx_out(const br_xxx_context *ctx, void *out)
+ * Complete the hash computation and write the result in the provided
+ * buffer. The output buffer MUST be large enough to accomodate the
+ * result. The context is NOT modified by this operation, so this
+ * function can be used to get a "partial hash" while still keeping
+ * the possibility of adding more bytes to the input.
+ *
+ * br_xxx_state(const br_xxx_context *ctx, void *out)
+ * Get a copy of the "current state" for the computation so far. For
+ * MD functions (MD5, SHA-1, SHA-2 family), this is the running state
+ * resulting from the processing of the last complete input block.
+ * Returned value is the current input length (in bytes).
+ *
+ * br_xxx_set_state(br_xxx_context *ctx, const void *stb, uint64_t count)
+ * Set the internal state to the provided values. The 'stb' and 'count'
+ * values shall match that which was obtained from br_xxx_state(). This
+ * restores the hash state only if the state values were at an
+ * appropriate block boundary. This does NOT set the 'vtable' pointer
+ * in the context.
+ *
+ * Context structures can be discarded without any explicit deallocation.
+ * Hash function implementations are purely software and don't reserve
+ * any resources outside of the context structure itself.
+ *
+ * Implemented hash functions are:
+ *
+ * Function Name Output length State length
+ *
+ * MD5 md5 16 16
+ * SHA-1 sha1 20 20
+ * SHA-224 sha224 28 32
+ * SHA-256 sha256 32 32
+ * SHA-384 sha384 48 64
+ * SHA-512 sha512 64 64
+ * MD5+SHA-1 md5sha1 36 36
+ *
+ * (MD5+SHA-1 is the concatenation of MD5 and SHA-1 computed over the
+ * same input; in the implementation, the internal data buffer is
+ * shared, thus making it more memory-efficient than separate MD5 and
+ * SHA-1. It can be useful in implementing SSL 3.0, TLS 1.0 and TLS
+ * 1.1.)
+ *
+ *
+ * An object-oriented API is also available: the first field of the
+ * context is a pointer to a br_hash_class structure, that has the
+ * following contents:
+ *
+ * context_size total size of the required context structure
+ * desc descriptor (see below)
+ * init context initialization or reset (function pointer)
+ * update process some more bytes (function pointer)
+ * out get hash output so far (function pointer)
+ * state get copy of internal state (function pointer)
+ * set_state reset the internal state (function pointer)
+ *
+ * The descriptor is a combination of the following elements:
+ * bits 0 to 7 hash algorithm identifier
+ * bits 8 to 14 hash output size (in bytes)
+ * bits 15 to 22 hash internal state size (in bytes)
+ * bits 23 to 26 log (base 2) of hash internal block size (in bytes)
+ * bit 28 1 if using MD padding, 0 otherwise
+ * bit 29 1 if MD padding uses a 128-bit bit length, 0 otherwise
+ * bit 30 1 if MD padding is big-endian, 0 otherwise
+ *
+ * For function 'xxx', the br_xxx_init() function sets the first field
+ * to a pointer to the relevant br_hash_class instance (i.e.
+ * br_xxx_vtable).
+ *
+ * Users of this object-oriented API may make the following assumptions:
+ * Hash output size is no more than 64 bytes.
+ * Hash internal state size is no more than 64 bytes.
+ * Internal block size is a power of two, no less than 2^4 and no more
+ * than 2^8.
+ * For functions that do not have an internal block size that is a
+ * power of 2, the relevant element is 0.
+ */
+
+typedef struct br_hash_class_ br_hash_class;
+struct br_hash_class_ {
+ size_t context_size;
+ uint32_t desc;
+ void (*init)(const br_hash_class **ctx);
+ void (*update)(const br_hash_class **ctx, const void *data, size_t len);
+ void (*out)(const br_hash_class *const *ctx, void *dst);
+ uint64_t (*state)(const br_hash_class *const *ctx, void *dst);
+ void (*set_state)(const br_hash_class **ctx,
+ const void *stb, uint64_t count);
+};
+
+#define BR_HASHDESC_ID(id) ((uint32_t)(id) << BR_HASHDESC_ID_OFF)
+#define BR_HASHDESC_ID_OFF 0
+#define BR_HASHDESC_ID_MASK 0xFF
+
+#define BR_HASHDESC_OUT(size) ((uint32_t)(size) << BR_HASHDESC_OUT_OFF)
+#define BR_HASHDESC_OUT_OFF 8
+#define BR_HASHDESC_OUT_MASK 0x7F
+
+#define BR_HASHDESC_STATE(size) ((uint32_t)(size) << BR_HASHDESC_STATE_OFF)
+#define BR_HASHDESC_STATE_OFF 15
+#define BR_HASHDESC_STATE_MASK 0xFF
+
+#define BR_HASHDESC_LBLEN(ls) ((uint32_t)(ls) << BR_HASHDESC_LBLEN_OFF)
+#define BR_HASHDESC_LBLEN_OFF 23
+#define BR_HASHDESC_LBLEN_MASK 0x0F
+
+#define BR_HASHDESC_MD_PADDING ((uint32_t)1 << 28)
+#define BR_HASHDESC_MD_PADDING_128 ((uint32_t)1 << 29)
+#define BR_HASHDESC_MD_PADDING_BE ((uint32_t)1 << 30)
+
+/*
+ * Specific hash functions.
+ *
+ * Rules for contexts:
+ * -- No interior pointer.
+ * -- No pointer to external dynamically allocated resources.
+ * -- First field is called 'vtable' and is a pointer to a
+ * const-qualified br_hash_class instance (pointer is set by init()).
+ * -- SHA-224 and SHA-256 contexts are identical.
+ * -- SHA-384 and SHA-512 contexts are identical.
+ *
+ * Thus, contexts can be moved and cloned to capture the hash function
+ * current state; and there is no need for any explicit "release" function.
+ */
+
+#define br_md5_ID 1
+#define br_md5_SIZE 16
+extern const br_hash_class br_md5_vtable;
+typedef struct {
+ const br_hash_class *vtable;
+ unsigned char buf[64];
+ uint64_t count;
+ uint32_t val[4];
+} br_md5_context;
+void br_md5_init(br_md5_context *ctx);
+void br_md5_update(br_md5_context *ctx, const void *data, size_t len);
+void br_md5_out(const br_md5_context *ctx, void *out);
+uint64_t br_md5_state(const br_md5_context *ctx, void *out);
+void br_md5_set_state(br_md5_context *ctx, const void *stb, uint64_t count);
+
+#define br_sha1_ID 2
+#define br_sha1_SIZE 20
+extern const br_hash_class br_sha1_vtable;
+typedef struct {
+ const br_hash_class *vtable;
+ unsigned char buf[64];
+ uint64_t count;
+ uint32_t val[5];
+} br_sha1_context;
+void br_sha1_init(br_sha1_context *ctx);
+void br_sha1_update(br_sha1_context *ctx, const void *data, size_t len);
+void br_sha1_out(const br_sha1_context *ctx, void *out);
+uint64_t br_sha1_state(const br_sha1_context *ctx, void *out);
+void br_sha1_set_state(br_sha1_context *ctx, const void *stb, uint64_t count);
+
+#define br_sha224_ID 3
+#define br_sha224_SIZE 28
+extern const br_hash_class br_sha224_vtable;
+typedef struct {
+ const br_hash_class *vtable;
+ unsigned char buf[64];
+ uint64_t count;
+ uint32_t val[8];
+} br_sha224_context;
+void br_sha224_init(br_sha224_context *ctx);
+void br_sha224_update(br_sha224_context *ctx, const void *data, size_t len);
+void br_sha224_out(const br_sha224_context *ctx, void *out);
+uint64_t br_sha224_state(const br_sha224_context *ctx, void *out);
+void br_sha224_set_state(br_sha224_context *ctx,
+ const void *stb, uint64_t count);
+
+#define br_sha256_ID 4
+#define br_sha256_SIZE 32
+extern const br_hash_class br_sha256_vtable;
+typedef br_sha224_context br_sha256_context;
+void br_sha256_init(br_sha256_context *ctx);
+#define br_sha256_update br_sha224_update
+void br_sha256_out(const br_sha256_context *ctx, void *out);
+#define br_sha256_state br_sha224_state
+#define br_sha256_set_state br_sha224_set_state
+
+#define br_sha384_ID 5
+#define br_sha384_SIZE 48
+extern const br_hash_class br_sha384_vtable;
+typedef struct {
+ const br_hash_class *vtable;
+ unsigned char buf[128];
+ uint64_t count;
+ uint64_t val[8];
+} br_sha384_context;
+void br_sha384_init(br_sha384_context *ctx);
+void br_sha384_update(br_sha384_context *ctx, const void *data, size_t len);
+void br_sha384_out(const br_sha384_context *ctx, void *out);
+uint64_t br_sha384_state(const br_sha384_context *ctx, void *out);
+void br_sha384_set_state(br_sha384_context *ctx,
+ const void *stb, uint64_t count);
+
+#define br_sha512_ID 6
+#define br_sha512_SIZE 64
+extern const br_hash_class br_sha512_vtable;
+typedef br_sha384_context br_sha512_context;
+void br_sha512_init(br_sha512_context *ctx);
+#define br_sha512_update br_sha384_update
+void br_sha512_out(const br_sha512_context *ctx, void *out);
+#define br_sha512_state br_sha384_state
+#define br_sha512_set_state br_sha384_set_state
+
+/*
+ * "md5sha1" is a special hash function that computes both MD5 and SHA-1
+ * on the same input, and produces a 36-byte output (MD5 and SHA-1
+ * concatenation, in that order). State size is also 36 bytes.
+ */
+#define br_md5sha1_ID 0
+#define br_md5sha1_SIZE 36
+extern const br_hash_class br_md5sha1_vtable;
+typedef struct {
+ const br_hash_class *vtable;
+ unsigned char buf[64];
+ uint64_t count;
+ uint32_t val_md5[4];
+ uint32_t val_sha1[5];
+} br_md5sha1_context;
+void br_md5sha1_init(br_md5sha1_context *ctx);
+void br_md5sha1_update(br_md5sha1_context *ctx, const void *data, size_t len);
+void br_md5sha1_out(const br_md5sha1_context *ctx, void *out);
+uint64_t br_md5sha1_state(const br_md5sha1_context *ctx, void *out);
+void br_md5sha1_set_state(br_md5sha1_context *ctx,
+ const void *stb, uint64_t count);
+
+/*
+ * The br_hash_compat_context type is a type which is large enough to
+ * serve as context for all standard hash functions defined above.
+ */
+typedef union {
+ const br_hash_class *vtable;
+ br_md5_context md5;
+ br_sha1_context sha1;
+ br_sha224_context sha224;
+ br_sha256_context sha256;
+ br_sha384_context sha384;
+ br_sha512_context sha512;
+} br_hash_compat_context;
+
+/*
+ * The multi-hasher is a construct that handles hashing of the same input
+ * data with several hash functions, with a single shared input buffer.
+ * It can handle MD5, SHA-1, SHA-224, SHA-256, SHA-384 and SHA-512
+ * simultaneously, though which functions are activated depends on
+ * the set implementation pointers.
+ */
+
+typedef struct {
+ unsigned char buf[128];
+ uint64_t count;
+ uint32_t val_32[25];
+ uint64_t val_64[16];
+ const br_hash_class *impl[6];
+} br_multihash_context;
+
+/*
+ * Clear a complete multihash context. This should always be called once
+ * on a given context, before setting implementation pointers.
+ */
+void br_multihash_zero(br_multihash_context *ctx);
+
+/*
+ * Set a hash function implementation, identified by ID.
+ */
+static inline void
+br_multihash_setimpl(br_multihash_context *ctx,
+ int id, const br_hash_class *impl)
+{
+ /*
+ * This code relies on hash functions ID being values 1 to 6,
+ * in the MD5 to SHA-512 order.
+ */
+ ctx->impl[id - 1] = impl;
+}
+
+/*
+ * Get the configured hash implementation, identified by ID. This returns
+ * NULL for unsupported hash implementations. The hash identifier MUST
+ * be a valid one (from br_md5_ID to br_sha512_ID, inclusive).
+ */
+static inline const br_hash_class *
+br_multihash_getimpl(const br_multihash_context *ctx, int id)
+{
+ return ctx->impl[id - 1];
+}
+
+/*
+ * Reset a multihash context. The hash functions for which implementation
+ * pointers have been set are reset and initialized.
+ */
+void br_multihash_init(br_multihash_context *ctx);
+
+/*
+ * Input some bytes into the context.
+ */
+void br_multihash_update(br_multihash_context *ctx,
+ const void *data, size_t len);
+
+/*
+ * Get the hash of the bytes injected so far, with the specified hash
+ * function. The hash function is given by ID (e.g. br_md5_ID for MD5).
+ * The hash output is written on 'dst'. The hash length is returned (in
+ * bytes); if the specified hash function is not implemented by this
+ * context, then this function returns 0.
+ *
+ * Obtaining the hash output does not invalidate the current hashing
+ * operation, thus "partial hashes" can be obtained.
+ */
+size_t br_multihash_out(const br_multihash_context *ctx, int id, void *dst);
+
+/*
+ * Type for a GHASH implementation. GHASH is a sort of keyed hash meant
+ * to be used to implement GCM in combination with a block cipher (with
+ * 16-byte blocks).
+ *
+ * The y[] array has length 16 bytes and is used for input and output; in
+ * a complete GHASH run, it starts with an all-zero value. h[] is a 16-byte
+ * value that serves as key (it is derived from the encryption key in GCM,
+ * using the block cipher). The data length (len) is expressed in bytes.
+ *
+ * If the data length is not a multiple of 16, then the data is implicitly
+ * padded with zeros up to the next multiple of 16. Thus, when using GHASH
+ * in GCM, this method may be called twice, for the associated data and
+ * for the ciphertext, respectively; the zero-padding implements exactly
+ * the GCM rules.
+ */
+typedef void (*br_ghash)(void *y, const void *h, const void *data, size_t len);
+
+/*
+ * Implementation of GHASH using normal 32x32->64 multiplications. It is
+ * constant-time (if multiplications are constant-time).
+ */
+void br_ghash_ctmul(void *y, const void *h, const void *data, size_t len);
+
+/*
+ * Implementation of GHASH using normal 32x32->32 multiplications; this
+ * may be faster than br_ghash_ctmul() on platforms for which the inner
+ * multiplication opcode does not yield the upper 32 bits of the product.
+ * It is constant-time (if multiplications are constant-time).
+ */
+void br_ghash_ctmul32(void *y, const void *h, const void *data, size_t len);
+
+/*
+ * Implementation of GHASH using 64x64->64 multiplications. It is
+ * constant-time (if multiplications are constant-time).
+ */
+void br_ghash_ctmul64(void *y, const void *h, const void *data, size_t len);
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+#ifndef BR_BEARSSL_HMAC_H__
+#define BR_BEARSSL_HMAC_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "bearssl_hash.h"
+
+/*
+ * HMAC
+ * ----
+ *
+ * HMAC is initialized with a key and an underlying hash function; it
+ * then fills a "key context". That context contains the processed
+ * key.
+ *
+ * With the key context, a HMAC context can be initialized to process
+ * the input bytes and obtain the MAC output. The key context is not
+ * modified during that process, and can be reused.
+ *
+ * IMPORTANT: HMAC shall be used only with functions that have the
+ * following properties:
+ * hash output size does not exceed 64 bytes
+ * hash internal state size does not exceed 64 bytes
+ * internal block length is a power of 2 between 16 and 256 bytes
+ */
+
+/*
+ * Key context.
+ */
+typedef struct {
+ const br_hash_class *dig_vtable;
+ unsigned char ksi[64], kso[64];
+} br_hmac_key_context;
+
+/*
+ * Initialize the key context with the provided key, using the hash function
+ * identified by digest_class.
+ */
+void br_hmac_key_init(br_hmac_key_context *kc,
+ const br_hash_class *digest_class, const void *key, size_t key_len);
+
+/*
+ * A helper structure that is big enough to accommodate all context
+ * structures for all hash functions for which HMAC is supported.
+ */
+typedef union {
+ const br_hash_class *vtable;
+ br_md5_context md5;
+ br_sha1_context sha1;
+ br_sha224_context sha224;
+ br_sha256_context sha256;
+ br_sha384_context sha384;
+ br_sha512_context sha512;
+} br_hmac_allhash_context;
+
+/*
+ * Context for an HMAC computation.
+ */
+typedef struct {
+ br_hmac_allhash_context dig;
+ unsigned char kso[64];
+ size_t out_len;
+} br_hmac_context;
+
+/*
+ * Initialize a HMAC context with a key context. The key context is
+ * unmodified. Relevant data from the key context is immediately copied;
+ * the key context can thus be independently reused, modified or released
+ * without impacting this HMAC computation.
+ *
+ * An explicit output length can be specified; the actual output length
+ * will be the minimum of that value and the natural HMAC output length.
+ * If out_len is 0, then the natural HMAC output length is selected.
+ */
+void br_hmac_init(br_hmac_context *ctx,
+ const br_hmac_key_context *kc, size_t out_len);
+
+/*
+ * Get the MAC output size. The context must have been initialized.
+ */
+#define br_hmac_size(ctx) ((ctx)->out_len)
+
+/*
+ * Process some more bytes.
+ */
+void br_hmac_update(br_hmac_context *ctx, const void *data, size_t len);
+
+/*
+ * Compute the HMAC output. The destination buffer MUST be large enough
+ * to accomodate the result. The context is NOT modified; further bytes
+ * may be processed. Thus, "partial HMAC" values can be efficiently
+ * obtained.
+ *
+ * Returned value is the output length (in bytes).
+ */
+size_t br_hmac_out(const br_hmac_context *ctx, void *out);
+
+/*
+ * Compute the HMAC output in constant time. Some extra input bytes are
+ * processed, then the output is computed. The extra input consists in
+ * the 'len' bytes pointed to by 'data'. The 'len' parameter must lie
+ * between 'min_len' and 'max_len' (inclusive); max_len bytes are
+ * actually read from 'data'. Computing time (and memory access pattern)
+ * will not depend upon the data bytes or the value of 'len'.
+ *
+ * The output is written in the 'out' buffer, that MUST be large enough
+ * to receive it.
+ *
+ * The difference max_len-min_len MUST be less than 2^30.
+ *
+ * This function computes the output properly only if the underlying
+ * hash function uses MD padding (i.e. MD5, SHA-1, SHA-224, SHA-256,
+ * SHA-384 or SHA-512).
+ *
+ * The provided context is NOT modified.
+ *
+ * Returned value is the MAC length (in bytes).
+ */
+size_t br_hmac_outCT(const br_hmac_context *ctx,
+ const void *data, size_t len, size_t min_len, size_t max_len,
+ void *out);
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+#ifndef BR_BEARSSL_PEM_H__
+#define BR_BEARSSL_PEM_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+/*
+ * Context for a PEM decoder.
+ */
+typedef struct {
+ /* CPU for the T0 virtual machine. */
+ struct {
+ uint32_t *dp;
+ uint32_t *rp;
+ const unsigned char *ip;
+ } cpu;
+ uint32_t dp_stack[32];
+ uint32_t rp_stack[32];
+ int err;
+
+ const unsigned char *hbuf;
+ size_t hlen;
+
+ void (*dest)(void *dest_ctx, const void *src, size_t len);
+ void *dest_ctx;
+
+ unsigned char event;
+ char name[128];
+ unsigned char buf[255];
+ size_t ptr;
+
+} br_pem_decoder_context;
+
+/*
+ * Initialise a PEM decoder structure.
+ */
+void br_pem_decoder_init(br_pem_decoder_context *ctx);
+
+/*
+ * Push some bytes into the decoder. Returned value is the number of
+ * bytes actually consumed; this may be less than the number of provided
+ * bytes if an event is produced. When an event is produced, it must
+ * be read (with br_pem_decoder_event()); until the event is read, this
+ * function will return 0.
+ */
+size_t br_pem_decoder_push(br_pem_decoder_context *ctx,
+ const void *data, size_t len);
+
+/*
+ * Set the receiver for decoded data. The provided function (with opaque
+ * context pointer) will be called with successive data chunks.
+ */
+static inline void
+br_pem_decoder_setdest(br_pem_decoder_context *ctx,
+ void (*dest)(void *dest_ctx, const void *src, size_t len),
+ void *dest_ctx)
+{
+ ctx->dest = dest;
+ ctx->dest_ctx = dest_ctx;
+}
+
+/*
+ * Get the last event. This is 0 if no event has been produced. Calling
+ * ths function clears the event and allows new source bytes to be
+ * processed.
+ */
+int br_pem_decoder_event(br_pem_decoder_context *ctx);
+
+/*
+ * This event is called when the start of a new object has been detected.
+ * The object name (normalised to uppercase) can be accessed with
+ * br_pem_decoder_name(). The caller MUST provide an appropriate receiver
+ * (with br_pem_decoder_setdest()) before sending new data bytes.
+ */
+#define BR_PEM_BEGIN_OBJ 1
+
+/*
+ * This event is called when the end of the current object is reached
+ * (normally).
+ */
+#define BR_PEM_END_OBJ 2
+
+/*
+ * This event is called when decoding fails while decoding an object.
+ * This formally closes the current object and brings the decoder back
+ * to the "out of any object" state. The offending line in the source
+ * is consumed.
+ */
+#define BR_PEM_ERROR 3
+
+/*
+ * Get the name of the encountered object. That name is normalised to
+ * uppercase (for ASCII characters).
+ */
+static inline const char *
+br_pem_decoder_name(br_pem_decoder_context *ctx)
+{
+ return ctx->name;
+}
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+#ifndef BR_BEARSSL_PRF_H__
+#define BR_BEARSSL_PRF_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+/*
+ * The TLS PRF
+ * -----------
+ *
+ * TLS 1.0 and 1.1 define a PRF that is based on both MD5 and SHA-1. This
+ * is implemented by the br_tls10_prf() function.
+ *
+ * TLS 1.2 redefines the PRF, using an explicit hash function. The
+ * br_tls12_sha256_prf() and br_tls12_sha384_prf() functions apply that
+ * PRF with, respectively, SHA-256 and SHA-384.
+ *
+ * The PRF always uses as input three parameters: a "secret" (some
+ * bytes), a "label" (ASCII string), and a "seed" (again some bytes).
+ * An arbitrary output length can be produced.
+ */
+
+void br_tls10_prf(void *dst, size_t len,
+ const void *secret, size_t secret_len,
+ const char *label, const void *seed, size_t seed_len);
+
+void br_tls12_sha256_prf(void *dst, size_t len,
+ const void *secret, size_t secret_len,
+ const char *label, const void *seed, size_t seed_len);
+
+void br_tls12_sha384_prf(void *dst, size_t len,
+ const void *secret, size_t secret_len,
+ const char *label, const void *seed, size_t seed_len);
+
+/*
+ * A convenient type name for a PRF implementation.
+ */
+typedef void (*br_tls_prf_impl)(void *dst, size_t len,
+ const void *secret, size_t secret_len,
+ const char *label, const void *seed, size_t seed_len);
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+#ifndef BR_BEARSSL_RAND_H__
+#define BR_BEARSSL_RAND_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+/*
+ * Pseudo-Random Generators
+ * ------------------------
+ *
+ * A PRNG is a state-based engine that outputs pseudo-random bytes on
+ * demand. It is initialized with an initial seed, and additional seed
+ * bytes can be added afterwards. Bytes produced depend on the seeds
+ * and also on the exact sequence of calls (including sizes requested
+ * for each call).
+ *
+ * An object-oriented API is defined, with rules similar to that of
+ * hash functions. The context structure for a PRNG must start with
+ * a pointer to the vtable. The vtable contains the following fields:
+ *
+ * context_size size of the context structure for this PRNG
+ * init initialize context with an initial seed
+ * generate produce some pseudo-random bytes
+ * update insert some additional seed
+ *
+ * Note that the init() method may accept additional parameters, provided
+ * as a 'const void *' pointer at API level. These additional parameters
+ * depend on the implemented PRNG.
+ */
+
+typedef struct br_prng_class_ br_prng_class;
+struct br_prng_class_ {
+ size_t context_size;
+ void (*init)(const br_prng_class **ctx, const void *params,
+ const void *seed, size_t seed_len);
+ void (*generate)(const br_prng_class **ctx, void *out, size_t len);
+ void (*update)(const br_prng_class **ctx,
+ const void *seed, size_t seed_len);
+};
+
+/*
+ * HMAC_DRBG is a pseudo-random number generator based on HMAC (with
+ * an underlying hash function). HMAC_DRBG is specified in NIST Special
+ * Publication 800-90A. It works as a stateful machine:
+ * -- It has an internal state.
+ * -- The state can be updated with additional "entropy" (some bytes
+ * provided from the outside).
+ * -- Each request is for some bits (up to some limit). For each request,
+ * an internal "reseed counter" is incremented.
+ * -- When the reseed counter reaches a given threshold, a reseed is
+ * necessary.
+ *
+ * Standard limits are quite high: each request can produce up to 2^19
+ * bits (i.e. 64 kB of data), and the threshold for the reseed counter
+ * is 2^48. In practice, we cannot really reach that reseed counter, so
+ * the implementation simply omits the counter. Similarly, we consider
+ * that it is up to callers NOT to ask for more than 64 kB of randomness
+ * in one go. Under these conditions, this implementation cannot fail,
+ * and thus functions need not return any status code.
+ *
+ * (Asking for more than 64 kB of data in one generate() call won't make
+ * the implementation fail, and, as far as we know, it will not induce
+ * any actual weakness; this is "merely" out of the formal usage range
+ * defined for HMAC_DRBG.)
+ *
+ * A dedicated context structure (caller allocated, as usual) contains
+ * the current PRNG state.
+ *
+ * For the OOP interface, the "additional parameters" are a pointer to
+ * the class of the hash function to use.
+ */
+
+typedef struct {
+ const br_prng_class *vtable;
+ unsigned char K[64];
+ unsigned char V[64];
+ const br_hash_class *digest_class;
+} br_hmac_drbg_context;
+
+extern const br_prng_class br_hmac_drbg_vtable;
+
+/*
+ * Initialize a HMAC_DRBG instance, with the provided initial seed (of
+ * 'len' bytes). The 'seed' used here is what is called, in SP 800-90A
+ * terminology, the concatenation of the "seed", "nonce" and
+ * "personalization string", in that order.
+ *
+ * Formally, the underlying digest can only be SHA-1 or one of the SHA-2
+ * functions. This implementation also works with any other implemented
+ * hash function (e.g. MD5), but such usage is non-standard and not
+ * recommended.
+ */
+void br_hmac_drbg_init(br_hmac_drbg_context *ctx,
+ const br_hash_class *digest_class, const void *seed, size_t len);
+
+/*
+ * Obtain some pseudorandom bits from HMAC_DRBG. The provided context
+ * is updated. The output bits are written in 'out' ('len' bytes). The
+ * size of the requested chunk of pseudorandom bits MUST NOT exceed
+ * 64 kB (the function won't fail if more bytes are requested, but
+ * the usage will be outside of the HMAC_DRBG specification limits).
+ */
+void br_hmac_drbg_generate(br_hmac_drbg_context *ctx, void *out, size_t len);
+
+/*
+ * Update an HMAC_DRBG instance with some new entropy. The extra 'seed'
+ * complements the current state but does not completely replace any
+ * previous seed. The process is such that pushing new entropy, even of
+ * questionable quality, will not make the output "less random" in any
+ * practical way.
+ */
+void br_hmac_drbg_update(br_hmac_drbg_context *ctx,
+ const void *seed, size_t len);
+
+/*
+ * Get the hash function implementation used by a given instance of
+ * HMAC_DRBG.
+ */
+static inline const br_hash_class *
+br_hmac_drbg_get_hash(const br_hmac_drbg_context *ctx)
+{
+ return ctx->digest_class;
+}
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+#ifndef BR_BEARSSL_RSA_H__
+#define BR_BEARSSL_RSA_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+/*
+ * RSA
+ * ---
+ *
+ * A RSA engine consists in two functions, for public-key and private-key
+ * operations (modular exponentiations). In both cases, the same buffer is
+ * used as source and destination.
+ *
+ * Key elements are provided as arrays of bytes, in big-endian unsigned
+ * encoding (leading zeros are correctly skipped, hence signed encodings
+ * can also be used). The source/destination array (x[]) is an array of
+ * bytes that, per PKCS#1 rules, MUST have the same length as the modulus,
+ * exactly: missing or extra leading bytes, even of value 0x00, are not
+ * tolerated for x[].
+ *
+ * Parameter validation: the engine MUST gracefully handle incorrect key
+ * parameters (e.g. an even modulus); it needs not detect all cases of
+ * incorrect key parameters. For public key operations, the engine MUST
+ * validate the length of x[] (it must match the numerical length, in
+ * bytes, of the modulus); it MUST also check that the provided x[]
+ * decodes to an integer that is numerically less than the modulus. For
+ * private key operation, the engine may assume that the length and
+ * contents of x[] are appropriate (it MUST NOT allow an invalid value
+ * to result in a buffer overflow, but an invalid input x[] may result
+ * in an undetected invalid output).
+ *
+ * Constant-time requirements: the following information may leak through
+ * execution time and memory access pattern:
+ * -- the actual bit length of the modulus;
+ * -- the actual bit length of each prime factor;
+ * -- the byte lengths as provided to the function calls.
+ */
+
+/*
+ * A structure type for a RSA public key, consisting in a modulus and
+ * a public exponent, encoded in unsigned big-endian format. The two
+ * arrays may be larger than needed; functions that accept a RSA public
+ * key are supposed to check the actual modulus length when needed.
+ */
+typedef struct {
+ unsigned char *n;
+ size_t nlen;
+ unsigned char *e;
+ size_t elen;
+} br_rsa_public_key;
+
+/*
+ * A structure type for a RSA private key. The key elements are:
+ * n_bitlen modulus bit length
+ * p prime modulus factor
+ * q other prime modulus factor (may be greater or lower than p)
+ * dp private exponent, reduced modulo p-1
+ * dq private exponent, reduced modulo q-1
+ * iq CRT coefficient: q*iq = 1 mod p.
+ */
+typedef struct {
+ uint32_t n_bitlen;
+ unsigned char *p;
+ size_t plen;
+ unsigned char *q;
+ size_t qlen;
+ unsigned char *dp;
+ size_t dplen;
+ unsigned char *dq;
+ size_t dqlen;
+ unsigned char *iq;
+ size_t iqlen;
+} br_rsa_private_key;
+
+/*
+ * Type for a public-key engine. The source buffer x[], of size xlen,
+ * is modified in place.
+ *
+ * Returned value is 1 on success, 0 on error.
+ *
+ * If the source buffer length (xlen) does not exactly match the modulus
+ * length, then an error is reported and x[] is unmodified.
+ */
+typedef uint32_t (*br_rsa_public)(unsigned char *x, size_t xlen,
+ const br_rsa_public_key *pk);
+
+/*
+ * Type for a RSA signature verification engine (PKCS#1 v1.5 signatures).
+ * Parameters are:
+ * -- The signature itself. The provided array is NOT modified.
+ * -- The encoded OID for the hash function. The provided array must begin
+ * with a single byte that contains the length of the OID value (in
+ * bytes), followed by exactly that many bytes.
+ * This parameter may be NULL, in which case the raw hash value should
+ * be used with the PKCS#1 v1.5 "type 1" padding (used in SSL/TLS up
+ * to TLS-1.1, with a 36-byte hash value).
+ * -- The hash output length, in bytes.
+ * -- The public key.
+ * -- An output buffer for the hash value. The caller must still compare
+ * it with the hash of the data over which the signature is computed.
+ *
+ * CONSTRAINTS:
+ * -- Hash length MUST be no more than 64 bytes.
+ * -- OID value length MUST be no more than 32 bytes (i.e. hash_oid[0]
+ * must have a value in the 0..32 range, inclusive).
+ *
+ * This function verifies that the signature length (xlen) matches the
+ * modulus length (this function returns 0 on mismatch). If the modulus
+ * size exceeds the maximum supported RSA size, then the function also
+ * returns 0.
+ *
+ * Returned value is 1 on success, 0 on error.
+ *
+ * Implementations of this type need not be constant-time.
+ */
+typedef uint32_t (*br_rsa_pkcs1_vrfy)(const unsigned char *x, size_t xlen,
+ const unsigned char *hash_oid, size_t hash_len,
+ const br_rsa_public_key *pk, unsigned char *hash_out);
+
+/*
+ * Type for a private-key engine. The x[] buffer is modified in place, and
+ * its length is inferred from the modulus length (x[] is assumed to have
+ * a length of (sk->n_bitlen+7)/8 bytes).
+ *
+ * Returned value is 1 on success, 0 on error.
+ */
+typedef uint32_t (*br_rsa_private)(unsigned char *x,
+ const br_rsa_private_key *sk);
+
+/*
+ * Type for a RSA signature generation engine (PKCS#1 v1.5 signatures).
+ * Parameters are:
+ * -- The encoded OID for the hash function. The provided array must begin
+ * with a single byte that contains the length of the OID value (in
+ * bytes), followed by exactly that many bytes.
+ * This parameter may be NULL, in which case the raw hash value should
+ * be used with the PKCS#1 v1.5 "type 1" padding (used in SSL/TLS up
+ * to TLS-1.1, with a 36-byte hash value).
+ * -- The hashed data, and length (in bytes).
+ * -- The private key.
+ * -- The output buffer.
+ *
+ * Returned value is 1 on success, 0 on error. Error conditions include
+ * a too small modulus for the provided hash OID and value, or some
+ * invalid key parameters. The signature length is exactly
+ * (sk->n_bitlen+7)/8 bytes.
+ *
+ * This function is expected to be constant-time with regards to the
+ * private key bytes (lengths of the modulus and the individual factors
+ * may leak, though) and to the hashed data.
+ */
+typedef uint32_t (*br_rsa_pkcs1_sign)(const unsigned char *hash_oid,
+ const unsigned char *hash, size_t hash_len,
+ const br_rsa_private_key *sk, unsigned char *x);
+
+/*
+ * RSA "i32" engine. Integers are internally represented as arrays of
+ * 32-bit integers, and the core multiplication primitive is the
+ * 32x32->64 multiplication.
+ */
+
+uint32_t br_rsa_i32_public(unsigned char *x, size_t xlen,
+ const br_rsa_public_key *pk);
+uint32_t br_rsa_i32_pkcs1_vrfy(const unsigned char *x, size_t xlen,
+ const unsigned char *hash_oid, size_t hash_len,
+ const br_rsa_public_key *pk, unsigned char *hash_out);
+uint32_t br_rsa_i32_private(unsigned char *x,
+ const br_rsa_private_key *sk);
+uint32_t br_rsa_i32_pkcs1_sign(const unsigned char *hash_oid,
+ const unsigned char *hash, size_t hash_len,
+ const br_rsa_private_key *sk, unsigned char *x);
+
+/*
+ * RSA "i31" engine. Similar to i32, but only 31 bits are used per 32-bit
+ * word. This uses slightly more stack space (about 4% more) and code
+ * space, but it quite faster.
+ */
+
+uint32_t br_rsa_i31_public(unsigned char *x, size_t xlen,
+ const br_rsa_public_key *pk);
+uint32_t br_rsa_i31_pkcs1_vrfy(const unsigned char *x, size_t xlen,
+ const unsigned char *hash_oid, size_t hash_len,
+ const br_rsa_public_key *pk, unsigned char *hash_out);
+uint32_t br_rsa_i31_private(unsigned char *x,
+ const br_rsa_private_key *sk);
+uint32_t br_rsa_i31_pkcs1_sign(const unsigned char *hash_oid,
+ const unsigned char *hash, size_t hash_len,
+ const br_rsa_private_key *sk, unsigned char *x);
+
+/*
+ * Perform RSA decryption for SSL/TLS. This function uses the provided core
+ * and private key to decrypt the message in data[] of size 'len'. The
+ * buffer is modified; the decryption result MUST have length 48, and
+ * is written into the first 48 bytes of data[].
+ *
+ * In success, this rturns 1. On error, 0 is returned, and the buffer
+ * contents are indeterminate.
+ */
+uint32_t br_rsa_ssl_decrypt(br_rsa_private core, const br_rsa_private_key *sk,
+ unsigned char *data, size_t len);
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+#ifndef BR_BEARSSL_SSL_H__
+#define BR_BEARSSL_SSL_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "bearssl_block.h"
+#include "bearssl_hash.h"
+#include "bearssl_hmac.h"
+#include "bearssl_prf.h"
+#include "bearssl_rand.h"
+#include "bearssl_x509.h"
+
+/*
+ * SSL
+ * ---
+ *
+ */
+
+/* Optimal input buffer size. */
+#define BR_SSL_BUFSIZE_INPUT (16384 + 325)
+
+/* Optimal output buffer size. */
+#define BR_SSL_BUFSIZE_OUTPUT (16384 + 85)
+
+/* Optimal buffer size for monodirectional engine
+ (shared input/output buffer). */
+#define BR_SSL_BUFSIZE_MONO BR_SSL_BUFSIZE_INPUT
+
+/* Optimal buffer size for bidirectional engine
+ (single buffer split into two separate input/output buffers). */
+#define BR_SSL_BUFSIZE_BIDI (BR_SSL_BUFSIZE_INPUT + BR_SSL_BUFSIZE_OUTPUT)
+
+/*
+ * Constants for known SSL/TLS protocol versions (SSL 3.0, TLS 1.0, TLS 1.1
+ * and TLS 1.2). Note that though there is a constant for SSL 3.0, that
+ * protocol version is not actually supported.
+ */
+#define BR_SSL30 0x0300
+#define BR_TLS10 0x0301
+#define BR_TLS11 0x0302
+#define BR_TLS12 0x0303
+
+/*
+ * Error constants. They are used to report the reason why a context has
+ * been marked as failed.
+ *
+ * Implementation note: SSL-level error codes should be in the 1..31
+ * range. The 32..63 range is for certificate decoding and validation
+ * errors. Received fatal alerts imply an error code in the 256..511 range.
+ */
+
+/* No error so far (0). */
+#define BR_ERR_OK 0
+
+/* Caller-provided parameter is incorrect. */
+#define BR_ERR_BAD_PARAM 1
+
+/* Operation requested by the caller cannot be applied with the current
+ context state (e.g. reading data while outgoing data is waiting to
+ be sent). */
+#define BR_ERR_BAD_STATE 2
+
+/* Incoming protocol or record version is unsupported. */
+#define BR_ERR_UNSUPPORTED_VERSION 3
+
+/* Incoming record version does not match the expected version. */
+#define BR_ERR_BAD_VERSION 4
+
+/* Incoming record length is invalid. */
+#define BR_ERR_BAD_LENGTH 5
+
+/* Incoming record is too large to be processed, or buffer is too small
+ for the handshake message to send. */
+#define BR_ERR_TOO_LARGE 6
+
+/* Decryption found an invalid padding, or the record MAC is not correct. */
+#define BR_ERR_BAD_MAC 7
+
+/* No initial entropy was provided, and none can be obtained from the OS. */
+#define BR_ERR_NO_RANDOM 8
+
+/* Incoming record type is unknown. */
+#define BR_ERR_UNKNOWN_TYPE 9
+
+/* Incoming record or message has wrong type with regards to the
+ current engine state. */
+#define BR_ERR_UNEXPECTED 10
+
+/* ChangeCipherSpec message from the peer has invalid contents. */
+#define BR_ERR_BAD_CCS 12
+
+/* Alert message from the peer has invalid contents (odd length). */
+#define BR_ERR_BAD_ALERT 13
+
+/* Incoming handshake message decoding failed. */
+#define BR_ERR_BAD_HANDSHAKE 14
+
+/* ServerHello contains a session ID which is larger than 32 bytes. */
+#define BR_ERR_OVERSIZED_ID 15
+
+/* Server wants to use a cipher suite that we did not claim to support.
+ This is also reported if we tried to advertise a cipher suite that
+ we do not support. */
+#define BR_ERR_BAD_CIPHER_SUITE 16
+
+/* Server wants to use a compression that we did not claim to support. */
+#define BR_ERR_BAD_COMPRESSION 17
+
+/* Server's max fragment length does not match client's. */
+#define BR_ERR_BAD_FRAGLEN 18
+
+/* Secure renegotiation failed. */
+#define BR_ERR_BAD_SECRENEG 19
+
+/* Server sent an extension type that we did not announce, or used the
+ same extension type several times in a single ServerHello. */
+#define BR_ERR_EXTRA_EXTENSION 20
+
+/* Invalid Server Name Indication contents (when used by the server,
+ this extension shall be empty). */
+#define BR_ERR_BAD_SNI 21
+
+/* Invalid ServerHelloDone from the server (length is not 0). */
+#define BR_ERR_BAD_HELLO_DONE 22
+
+/* Internal limit exceeded (e.g. server's public key is too large). */
+#define BR_ERR_LIMIT_EXCEEDED 23
+
+/* Finished message from peer does not match the expected value. */
+#define BR_ERR_BAD_FINISHED 24
+
+/* Session resumption attempt with distinct version or cipher suite. */
+#define BR_ERR_RESUME_MISMATCH 25
+
+/* Unsupported or invalid algorithm (ECDHE curve, signature algorithm,
+ hash function). */
+#define BR_ERR_INVALID_ALGORITHM 26
+
+/* Invalid signature on ServerKeyExchange message. */
+#define BR_ERR_BAD_SIGNATURE 27
+
+/* I/O error or premature close on underlying transport stream. This
+ error code is set only by the simplified I/O API ("br_sslio_*"). */
+#define BR_ERR_IO 31
+
+/* When a fatal alert is received from the peer, the alert value is added
+ to this constant. */
+#define BR_ERR_RECV_FATAL_ALERT 256
+
+/* When a fatal alert is sent to the peer, the alert value is added
+ to this constant. */
+#define BR_ERR_SEND_FATAL_ALERT 512
+
+/* ===================================================================== */
+
+/*
+ * The decryption engine for incoming records is an object that implements
+ * the following functions:
+ *
+ * check_length test whether the provided record length is valid
+ * decrypt decrypt and verify the provided record
+ *
+ * The decrypt() function receives as parameters a pointer to its context
+ * structure, the record type, the record version, a pointer to the
+ * start of the record payload, and a pointer to a word containing the
+ * payload length. The decrypt() function may assume that the length is
+ * proper (check_length() was called and returned 1). On success, a
+ * pointer to the first plaintext byte is returned, and *len is adjusted
+ * to contain the plaintext length; on error, NULL is returned.
+ *
+ * The decryption engine is responsible for keeping track of the record
+ * sequence number.
+ */
+typedef struct br_sslrec_in_class_ br_sslrec_in_class;
+struct br_sslrec_in_class_ {
+ size_t context_size;
+ int (*check_length)(const br_sslrec_in_class *const *ctx,
+ size_t record_len);
+ unsigned char *(*decrypt)(const br_sslrec_in_class **ctx,
+ int record_type, unsigned version,
+ void *payload, size_t *len);
+};
+
+/*
+ * The encryption engine for outgoing records is an object that implements
+ * the following functions:
+ *
+ * max_plaintext get start and end offsets for payload
+ * encrypt encrypt and apply MAC on current record
+ *
+ * The max_plaintext() function receives as inputs the start and end
+ * of the buffer where the payload will be stored; this function assumes
+ * that there will be room for a record header (5 bytes) BEFORE the
+ * offset specified by *start. The max_plaintext() function then adjusts
+ * the two offsets to designate the area for the plaintext.
+ *
+ * The encrypt() function assumes that the provided plaintext data is
+ * in a buffer with enough room before and after the data chunk to
+ * receive the needed headers (i.e. the plaintext is at offsets which
+ * were computed by an earlier call to max_plaintext()). It returns
+ * a pointer to the start of the encrypted record, and writes the
+ * encrypted record length in '*len' (that length includes the record
+ * header).
+ *
+ * The encryption engine MUST fill the record header. If the engine
+ * performs a "split" into several records, then the successive records
+ * MUST be consecutive in RAM; the returned length is thus the sum of
+ * the individual record lengths.
+ *
+ * The encryption engine is responsible for keeping track of the record
+ * sequence number.
+ */
+typedef struct br_sslrec_out_class_ br_sslrec_out_class;
+struct br_sslrec_out_class_ {
+ size_t context_size;
+ void (*max_plaintext)(const br_sslrec_out_class *const *ctx,
+ size_t *start, size_t *end);
+ unsigned char *(*encrypt)(const br_sslrec_out_class **ctx,
+ int record_type, unsigned version,
+ void *plaintext, size_t *len);
+};
+
+/*
+ * An outgoing no-encryption engine is defined, to process outgoing
+ * records before completion of the initial handshake.
+ */
+typedef struct {
+ const br_sslrec_out_class *vtable;
+} br_sslrec_out_clear_context;
+extern const br_sslrec_out_class br_sslrec_out_clear_vtable;
+
+/* ===================================================================== */
+
+/*
+ * An engine for processing incoming records with a block cipher in
+ * CBC mode has an extra initialization function, that takes as inputs:
+ * -- a block cipher (CBC decryption) and its key;
+ * -- a hash function for HMAC, with the MAC key and output length;
+ * -- an optional initial IV.
+ * If the IV is not provided (the 'iv' parameter is NULL), then the
+ * engine will use an explicit per-record IV (as is mandated in TLS 1.1+).
+ *
+ * The initialization function is responsible for setting the 'vtable'
+ * field of the context.
+ */
+typedef struct br_sslrec_in_cbc_class_ br_sslrec_in_cbc_class;
+struct br_sslrec_in_cbc_class_ {
+ br_sslrec_in_class inner;
+ void (*init)(const br_sslrec_in_cbc_class **ctx,
+ const br_block_cbcdec_class *bc_impl,
+ const void *bc_key, size_t bc_key_len,
+ const br_hash_class *dig_impl,
+ const void *mac_key, size_t mac_key_len, size_t mac_out_len,
+ const void *iv);
+};
+
+/*
+ * An engine for processing outgoing records with a block cipher in
+ * CBC mode has an extra initialization function, that takes as inputs:
+ * -- a block cipher (CBC encryption) and its key;
+ * -- a hash function for HMAC, with the MAC key and output length;
+ * -- an optional initial IV.
+ * If the IV is not provided (the 'iv' parameter is NULL), then the
+ * engine will use an explicit per-record IV (as is mandated in TLS 1.1+).
+ *
+ * The initialization function is responsible for setting the 'vtable'
+ * field of the context.
+ */
+typedef struct br_sslrec_out_cbc_class_ br_sslrec_out_cbc_class;
+struct br_sslrec_out_cbc_class_ {
+ br_sslrec_out_class inner;
+ void (*init)(const br_sslrec_out_cbc_class **ctx,
+ const br_block_cbcenc_class *bc_impl,
+ const void *bc_key, size_t bc_key_len,
+ const br_hash_class *dig_impl,
+ const void *mac_key, size_t mac_key_len, size_t mac_out_len,
+ const void *iv);
+};
+
+/*
+ * Context structure for decrypting incoming records with CBC + HMAC.
+ */
+typedef struct {
+ const br_sslrec_in_cbc_class *vtable;
+ uint64_t seq;
+ union {
+ const br_block_cbcdec_class *vtable;
+ br_aes_gen_cbcdec_keys aes;
+ br_des_gen_cbcdec_keys des;
+ } bc;
+ br_hmac_key_context mac;
+ size_t mac_len;
+ unsigned char iv[16];
+ int explicit_IV;
+} br_sslrec_in_cbc_context;
+extern const br_sslrec_in_cbc_class br_sslrec_in_cbc_vtable;
+
+/*
+ * Context structure for encrypting outgoing records with CBC + HMAC.
+ */
+typedef struct {
+ const br_sslrec_out_cbc_class *vtable;
+ uint64_t seq;
+ union {
+ const br_block_cbcenc_class *vtable;
+ br_aes_gen_cbcenc_keys aes;
+ br_des_gen_cbcenc_keys des;
+ } bc;
+ br_hmac_key_context mac;
+ size_t mac_len;
+ unsigned char iv[16];
+ int explicit_IV;
+} br_sslrec_out_cbc_context;
+extern const br_sslrec_out_cbc_class br_sslrec_out_cbc_vtable;
+
+/* ===================================================================== */
+
+/*
+ * An engine for processing incoming records with a block cipher in
+ * GCM mode has an extra initialization function, that takes as inputs:
+ * -- a block cipher (CTR) and its key;
+ * -- a GHASH implementation;
+ * -- an initial IV (4 bytes).
+ *
+ * The initialization function is responsible for setting the 'vtable'
+ * field of the context.
+ */
+typedef struct br_sslrec_in_gcm_class_ br_sslrec_in_gcm_class;
+struct br_sslrec_in_gcm_class_ {
+ br_sslrec_in_class inner;
+ void (*init)(const br_sslrec_in_gcm_class **ctx,
+ const br_block_ctr_class *bc_impl,
+ const void *key, size_t key_len,
+ br_ghash gh_impl,
+ const void *iv);
+};
+
+/*
+ * An engine for processing outgoing records with a block cipher in
+ * GCM mode has an extra initialization function, that takes as inputs:
+ * -- a block cipher (CTR) and its key;
+ * -- a GHASH implementation;
+ * -- an initial IV (4 bytes).
+ *
+ * The initialization function is responsible for setting the 'vtable'
+ * field of the context.
+ */
+typedef struct br_sslrec_out_gcm_class_ br_sslrec_out_gcm_class;
+struct br_sslrec_out_gcm_class_ {
+ br_sslrec_out_class inner;
+ void (*init)(const br_sslrec_out_gcm_class **ctx,
+ const br_block_ctr_class *bc_impl,
+ const void *key, size_t key_len,
+ br_ghash gh_impl,
+ const void *iv);
+};
+
+/*
+ * We use the same context structure for incoming and outgoing records
+ * with GCM, because it allows internal code sharing.
+ */
+typedef struct {
+ union {
+ const void *gen;
+ const br_sslrec_in_gcm_class *in;
+ const br_sslrec_out_gcm_class *out;
+ } vtable;
+ uint64_t seq;
+ union {
+ const br_block_ctr_class *vtable;
+ br_aes_gen_ctr_keys aes;
+ } bc;
+ br_ghash gh;
+ unsigned char iv[4];
+ unsigned char h[16];
+} br_sslrec_gcm_context;
+
+extern const br_sslrec_in_gcm_class br_sslrec_in_gcm_vtable;
+extern const br_sslrec_out_gcm_class br_sslrec_out_gcm_vtable;
+
+/* ===================================================================== */
+
+/*
+ * Type for session parameters, to be saved for session resumption.
+ */
+typedef struct {
+ unsigned char session_id[32];
+ unsigned char session_id_len;
+ uint16_t version;
+ uint16_t cipher_suite;
+ unsigned char master_secret[48];
+} br_ssl_session_parameters;
+
+/*
+ * Maximum numnber of cipher suites supported by a client or server.
+ */
+#define BR_MAX_CIPHER_SUITES 40
+
+/*
+ * Context structure for SSL engine. This is common to the client and
+ * server; the engine manages records, including alerts, closures, and
+ * transitions to new encryption/MAC algorithms. Processing of handshake
+ * records is delegated to externally provided code. This structure
+ * should not be used directly, but is meant to be included as first
+ * field of the context structures for SSL clients and servers.
+ */
+typedef struct {
+
+ /*
+ * The error code. When non-zero, then the state is "failed" and
+ * no I/O may occur until reset.
+ */
+ int err;
+
+ /*
+ * Configured I/O buffers. They are either disjoint, or identical.
+ */
+ unsigned char *ibuf, *obuf;
+ size_t ibuf_len, obuf_len;
+
+ /*
+ * Maximum fragment length applies to outgoing records; incoming
+ * records can be processed as long as they fit in the input
+ * buffer. It is guaranteed that incoming records at least as big
+ * as max_frag_len can be processed.
+ */
+ uint16_t max_frag_len;
+ unsigned char log_max_frag_len;
+ unsigned char peer_log_max_frag_len;
+
+ /*
+ * Buffering management registers.
+ */
+ size_t ixa, ixb, ixc;
+ size_t oxa, oxb, oxc;
+ unsigned char iomode;
+ unsigned char incrypt;
+
+ /*
+ * Shutdown flag: when set to non-zero, incoming record bytes
+ * will not be accepted anymore. This is used after a close_notify
+ * has been received: afterwards, the engine no longer claims that
+ * it could receive bytes from the transport medium.
+ */
+ unsigned char shutdown_recv;
+
+ /*
+ * 'record_type_in' is set to the incoming record type when the
+ * record header has been received.
+ * 'record_type_out' is used to make the next outgoing record
+ * header when it is ready to go.
+ */
+ unsigned char record_type_in, record_type_out;
+
+ /*
+ * When a record is received, its version is extracted:
+ * -- if 'version_in' is 0, then it is set to the received version;
+ * -- otherwise, if the received version is not identical to
+ * the 'version_in' contents, then a failure is reported.
+ *
+ * This implements the SSL requirement that all records shall
+ * use the negotiated protocol version, once decided (in the
+ * ServerHello). It is up to the handshake handler to adjust this
+ * field when necessary.
+ */
+ uint16_t version_in;
+
+ /*
+ * 'version_out' is used when the next outgoing record is ready
+ * to go.
+ */
+ uint16_t version_out;
+
+ /*
+ * Record handler contexts.
+ */
+ union {
+ const br_sslrec_in_class *vtable;
+ br_sslrec_in_cbc_context cbc;
+ br_sslrec_gcm_context gcm;
+ } in;
+ union {
+ const br_sslrec_out_class *vtable;
+ br_sslrec_out_clear_context clear;
+ br_sslrec_out_cbc_context cbc;
+ br_sslrec_gcm_context gcm;
+ } out;
+
+ /*
+ * The "application data" flag. It is set when application data
+ * can be exchanged, cleared otherwise.
+ */
+ unsigned char application_data;
+
+ /*
+ * Context RNG.
+ */
+ br_hmac_drbg_context rng;
+ int rng_init_done;
+ int rng_os_rand_done;
+
+ /*
+ * Supported minimum and maximum versions, and cipher suites.
+ */
+ uint16_t version_min;
+ uint16_t version_max;
+ uint16_t suites_buf[BR_MAX_CIPHER_SUITES];
+ unsigned char suites_num;
+
+ /*
+ * For clients, the server name to send as a SNI extension. For
+ * servers, the name received in the SNI extension (if any).
+ */
+ char server_name[256];
+
+ /*
+ * "Security parameters". These are filled by the handshake
+ * handler, and used when switching encryption state.
+ */
+ unsigned char client_random[32];
+ unsigned char server_random[32];
+ /* obsolete
+ unsigned char session_id[32];
+ unsigned char session_id_len;
+ uint16_t version;
+ uint16_t cipher_suite;
+ unsigned char master_secret[48];
+ */
+ br_ssl_session_parameters session;
+
+ /*
+ * ECDHE elements: curve and point from the peer. The server also
+ * uses that buffer for the point to send to the client.
+ */
+ unsigned char ecdhe_curve;
+ unsigned char ecdhe_point[133];
+ unsigned char ecdhe_point_len;
+
+ /*
+ * Secure renegotiation (RFC 5746): 'reneg' can be:
+ * 0 first handshake (server support is not known)
+ * 1 server does not support secure renegotiation
+ * 2 server supports secure renegotiation
+ *
+ * The saved_finished buffer contains the client and the
+ * server "Finished" values from the last handshake, in
+ * that order (12 bytes each).
+ */
+ unsigned char reneg;
+ unsigned char saved_finished[24];
+
+ /*
+ * Context variables for the handshake processor.
+ * The 'pad' must be large enough to accommodate an
+ * RSA-encrypted pre-master secret, or a RSA signature on
+ * key exchange parameters; since we want to support up to
+ * RSA-4096, this means at least 512 bytes.
+ * (Other pad usages require its length to be at least 256.)
+ */
+ struct {
+ uint32_t *dp;
+ uint32_t *rp;
+ const unsigned char *ip;
+ } cpu;
+ uint32_t dp_stack[32];
+ uint32_t rp_stack[32];
+ unsigned char pad[512];
+ unsigned char *hbuf_in, *hbuf_out, *saved_hbuf_out;
+ size_t hlen_in, hlen_out;
+ void (*hsrun)(void *ctx);
+
+ /*
+ * The 'action' value communicates OOB information between the
+ * engine and the handshake processor.
+ *
+ * From the engine:
+ * 0 invocation triggered by I/O
+ * 1 invocation triggered by explicit close
+ * 2 invocation triggered by explicit renegotiation
+ */
+ unsigned char action;
+
+ /*
+ * State for alert messages. Value is either 0, or the value of
+ * the alert level byte (level is either 1 for warning, or 2 for
+ * fatal; we convert all other values to 'fatal').
+ */
+ unsigned char alert;
+
+ /*
+ * Closure flags. This flag is set when a close_notify has been
+ * received from the peer.
+ */
+ unsigned char close_received;
+
+ /*
+ * Multi-hasher for the handshake messages. The handshake handler
+ * is responsible for resetting it when appropriate.
+ */
+ br_multihash_context mhash;
+
+ /*
+ * Pointer to the X.509 engine. The engine is supposed to be
+ * already initialized. It is used to validate the peer's
+ * certificate.
+ */
+ const br_x509_class **x509ctx;
+
+ /*
+ * Pointers to implementations; left to NULL for unsupported
+ * functions. For the raw hash functions, implementations are
+ * referenced from the multihasher (mhash field).
+ */
+ br_tls_prf_impl prf10;
+ br_tls_prf_impl prf_sha256;
+ br_tls_prf_impl prf_sha384;
+ const br_block_cbcenc_class *iaes_cbcenc;
+ const br_block_cbcdec_class *iaes_cbcdec;
+ const br_block_ctr_class *iaes_ctr;
+ const br_block_cbcenc_class *ides_cbcenc;
+ const br_block_cbcdec_class *ides_cbcdec;
+ br_ghash ighash;
+ const br_sslrec_in_cbc_class *icbc_in;
+ const br_sslrec_out_cbc_class *icbc_out;
+ const br_sslrec_in_gcm_class *igcm_in;
+ const br_sslrec_out_gcm_class *igcm_out;
+ const br_ec_impl *iec;
+
+} br_ssl_engine_context;
+
+/*
+ * Set the minimum and maximum supported protocol versions.
+ */
+static inline void
+br_ssl_engine_set_versions(br_ssl_engine_context *cc,
+ unsigned version_min, unsigned version_max)
+{
+ cc->version_min = version_min;
+ cc->version_max = version_max;
+}
+
+/*
+ * Set the list of cipher suites advertised by this context. The provided
+ * array is copied into the context. It is the caller responsibility
+ * to ensure that all provided suites will be supported by the context.
+ */
+void br_ssl_engine_set_suites(br_ssl_engine_context *cc,
+ const uint16_t *suites, size_t suites_num);
+
+/*
+ * Set the X.509 engine. The context should be already initialized and
+ * ready to process a new chain.
+ */
+static inline void
+br_ssl_engine_set_x509(br_ssl_engine_context *cc, const br_x509_class **x509ctx)
+{
+ cc->x509ctx = x509ctx;
+}
+
+/*
+ * Set a hash function implementation (by ID).
+ */
+static inline void
+br_ssl_engine_set_hash(br_ssl_engine_context *ctx,
+ int id, const br_hash_class *impl)
+{
+ br_multihash_setimpl(&ctx->mhash, id, impl);
+}
+
+/*
+ * Get a hash function implementation (by ID).
+ */
+static inline const br_hash_class *
+br_ssl_engine_get_hash(br_ssl_engine_context *ctx, int id)
+{
+ return br_multihash_getimpl(&ctx->mhash, id);
+}
+
+/*
+ * Set the PRF implementation (for TLS 1.0 and 1.1).
+ */
+static inline void
+br_ssl_engine_set_prf10(br_ssl_engine_context *cc, br_tls_prf_impl impl)
+{
+ cc->prf10 = impl;
+}
+
+/*
+ * Set the PRF implementation (for TLS 1.2, with SHA-256).
+ */
+static inline void
+br_ssl_engine_set_prf_sha256(br_ssl_engine_context *cc, br_tls_prf_impl impl)
+{
+ cc->prf_sha256 = impl;
+}
+
+/*
+ * Set the PRF implementation (for TLS 1.2, with SHA-384).
+ */
+static inline void
+br_ssl_engine_set_prf_sha384(br_ssl_engine_context *cc, br_tls_prf_impl impl)
+{
+ cc->prf_sha384 = impl;
+}
+
+/*
+ * Set the AES/CBC implementations.
+ */
+static inline void
+br_ssl_engine_set_aes_cbc(br_ssl_engine_context *cc,
+ const br_block_cbcenc_class *impl_enc,
+ const br_block_cbcdec_class *impl_dec)
+{
+ cc->iaes_cbcenc = impl_enc;
+ cc->iaes_cbcdec = impl_dec;
+}
+
+/*
+ * Set the AES/CTR implementation.
+ */
+static inline void
+br_ssl_engine_set_aes_ctr(br_ssl_engine_context *cc,
+ const br_block_ctr_class *impl)
+{
+ cc->iaes_ctr = impl;
+}
+
+/*
+ * Set the 3DES/CBC implementations.
+ */
+static inline void
+br_ssl_engine_set_des_cbc(br_ssl_engine_context *cc,
+ const br_block_cbcenc_class *impl_enc,
+ const br_block_cbcdec_class *impl_dec)
+{
+ cc->ides_cbcenc = impl_enc;
+ cc->ides_cbcdec = impl_dec;
+}
+
+/*
+ * Set the GHASH implementation (for GCM).
+ */
+static inline void
+br_ssl_engine_set_ghash(br_ssl_engine_context *cc, br_ghash impl)
+{
+ cc->ighash = impl;
+}
+
+/*
+ * Set the CBC+HMAC record processor implementations.
+ */
+static inline void
+br_ssl_engine_set_cbc(br_ssl_engine_context *cc,
+ const br_sslrec_in_cbc_class *impl_in,
+ const br_sslrec_out_cbc_class *impl_out)
+{
+ cc->icbc_in = impl_in;
+ cc->icbc_out = impl_out;
+}
+
+/*
+ * Set the GCM record processor implementations.
+ */
+static inline void
+br_ssl_engine_set_gcm(br_ssl_engine_context *cc,
+ const br_sslrec_in_gcm_class *impl_in,
+ const br_sslrec_out_gcm_class *impl_out)
+{
+ cc->igcm_in = impl_in;
+ cc->igcm_out = impl_out;
+}
+
+/*
+ * Set the ECC core operations implementation. The 'iec' parameter
+ * points to the core EC code used for both ECDHE and ECDSA.
+ */
+static inline void
+br_ssl_engine_set_ec(br_ssl_engine_context *cc, const br_ec_impl *iec)
+{
+ cc->iec = iec;
+}
+
+/*
+ * Set the I/O buffer for a SSL engine. Once this call has been made,
+ * br_ssl_client_reset() or br_ssl_server_reset() must be called before
+ * using the context.
+ *
+ * If 'bidi' is 1, then the buffer will be internally split to support
+ * concurrent input and output; otherwise, the caller will be responsible
+ * for reading all buffered incoming data before writing. The latter
+ * case makes support of HTTPS pipelining difficult, thus bidirectional
+ * buffering is recommended if the RAM can be spared.
+ *
+ * The BR_SSL_BUFSIZE_MONO and BR_SSL_BUFSIZE_BIDI macros yield optimal
+ * buffer sizes for the monodirectional and bidirectional cases,
+ * respectively. If using optimal sizes (or larger), then records with
+ * the maximum length supported by the TLS standard will be accepted
+ * and emitted.
+ */
+void br_ssl_engine_set_buffer(br_ssl_engine_context *cc,
+ void *iobuf, size_t iobuf_len, int bidi);
+
+/*
+ * Set the I/O buffers for a SSL engine. This call sets two buffers, for
+ * concurrent input and output. The two buffers MUST be disjoint. Once
+ * this call has been made, br_ssl_client_reset() or
+ * br_ssl_server_reset() must be called before using the context.
+ *
+ * The BR_SSL_BUFSIZE_INPUT and BR_SSL_BUFSIZE_OUTPUT macros evaluate to
+ * optimal sizes for the input and output buffers, respectively. If
+ * using optimal sizes (or larger), then records with the maximum length
+ * supported by the TLS standard will be accepted and emitted.
+ */
+void br_ssl_engine_set_buffers_bidi(br_ssl_engine_context *cc,
+ void *ibuf, size_t ibuf_len, void *obuf, size_t obuf_len);
+
+/*
+ * Inject some "initial entropy" in the context. This entropy will be added
+ * to what can be obtained from the underlying operating system, if that
+ * OS is supported.
+ *
+ * This function may be called several times; all injected entropy chunks
+ * are cumulatively mixed.
+ *
+ * If entropy gathering from the OS is supported and compiled in, then this
+ * step is optional. Otherwise, it is mandatory to inject randomness, and
+ * the caller MUST take care to push (as one or several successive calls)
+ * enough entropy to achieve cryptographic resistance (at least 80 bits,
+ * preferably 128 or more). The engine will report an error if no entropy
+ * was provided and none can be obtained from the OS.
+ *
+ * Take care that this function cannot assess the cryptographic quality of
+ * the provided bytes.
+ *
+ * In all generality, "entropy" must here be considered to mean "that
+ * which the attacker cannot predict". If your OS/architecture does not
+ * have a suitable source of randomness, then you can make do with the
+ * combination of a large enough secret value (possibly a copy of an
+ * asymmetric private key that you also store on the system) AND a
+ * non-repeating value (e.g. current time, provided that the local clock
+ * cannot be reset or altered by the attacker).
+ */
+void br_ssl_engine_inject_entropy(br_ssl_engine_context *cc,
+ const void *data, size_t len);
+
+/*
+ * Get the "server name" in this engine. For clients, this is the name
+ * provided with br_ssl_client_reset(); for servers, this is the name
+ * received from the client as part of the ClientHello message. If there
+ * is no such name (e.g. the client did not send an SNI extension) then
+ * the returned string is empty (returned pointer points to a byte of
+ * value 0).
+ */
+static inline const char *
+br_ssl_engine_get_server_name(br_ssl_engine_context *cc)
+{
+ return cc->server_name;
+}
+
+/*
+ * An SSL engine (client or server) has, at any time, a state which is
+ * the combination of zero, one or more of these flags:
+ *
+ * BR_SSL_CLOSED engine is finished, no more I/O (until next reset)
+ * BR_SSL_SENDREC engine has some bytes to send to the peer
+ * BR_SSL_RECVREC engine expects some bytes from the peer
+ * BR_SSL_SENDAPP engine may receive application data to send (or flush)
+ * BR_SSL_RECVAPP engine has obtained some application data from the peer,
+ * that should be read by the caller
+ *
+ * If no flag at all is set (state value is 0), then the engine is not
+ * fully initialized yet.
+ *
+ * The BR_SSL_CLOSED flag is exclusive; when it is set, no other flag is set.
+ * To distinguish between a normal closure and an error, use
+ * br_ssl_engine_last_error().
+ *
+ * Generally speaking, BR_SSL_SENDREC and BR_SSL_SENDAPP are mutually
+ * exclusive: the input buffer, at any point, either accumulates
+ * plaintext data, or contains an assembled record that is being sent.
+ * Similarly, BR_SSL_RECVREC and BR_SSL_RECVAPP are mutually exclusive.
+ * This may change in a future library version.
+ */
+
+#define BR_SSL_CLOSED 0x0001
+#define BR_SSL_SENDREC 0x0002
+#define BR_SSL_RECVREC 0x0004
+#define BR_SSL_SENDAPP 0x0008
+#define BR_SSL_RECVAPP 0x0010
+
+/*
+ * Get the current engine state.
+ */
+unsigned br_ssl_engine_current_state(const br_ssl_engine_context *cc);
+
+/*
+ * Get the engine error indicator. This is BR_ERR_OK (0) if no error was
+ * encountered since the last call to br_ssl_client_reset() or
+ * br_ssl_server_reset(). Only these calls clear the error indicator.
+ */
+static inline int
+br_ssl_engine_last_error(const br_ssl_engine_context *cc)
+{
+ return cc->err;
+}
+
+/*
+ * There are four I/O operations, each identified by a symbolic name:
+ *
+ * sendapp inject application data in the engine
+ * recvapp retrieving application data from the engine
+ * sendrec sending records on the transport medium
+ * recvrec receiving records from the transport medium
+ *
+ * Terminology works thus: in a layered model where the SSL engine sits
+ * between the application and the network, "send" designates operations
+ * where bytes flow from application to network, and "recv" for the
+ * reverse operation. Application data (the plaintext that is to be
+ * conveyed through SSL) is "app", while encrypted records are "rec".
+ * Note that from the SSL engine point of view, "sendapp" and "recvrec"
+ * designate bytes that enter the engine ("inject" operation), while
+ * "recvapp" and "sendrec" designate bytes that exit the engine
+ * ("extract" operation).
+ *
+ * For the operation 'xxx', two functions are defined:
+ *
+ * br_ssl_engine_xxx_buf
+ * Returns a pointer and length to the buffer to use for that
+ * operation. '*len' is set to the number of bytes that may be read
+ * from the buffer (extract operation) or written to the buffer
+ * (inject operation). If no byte may be exchanged for that operation
+ * at that point, then '*len' is set to zero, and NULL is returned.
+ * The engine state is unmodified by this call.
+ *
+ * br_ssl_engine_xxx_ack
+ * Informs the engine that 'len' bytes have been read from the buffer
+ * (extract operation) or written to the buffer (inject operation).
+ * The 'len' value MUST NOT be zero. The 'len' value MUST NOT exceed
+ * that which was obtained from a preceeding br_ssl_engine_xxx_buf()
+ * call.
+ */
+
+unsigned char *br_ssl_engine_sendapp_buf(
+ const br_ssl_engine_context *cc, size_t *len);
+void br_ssl_engine_sendapp_ack(br_ssl_engine_context *cc, size_t len);
+
+unsigned char *br_ssl_engine_recvapp_buf(
+ const br_ssl_engine_context *cc, size_t *len);
+void br_ssl_engine_recvapp_ack(br_ssl_engine_context *cc, size_t len);
+
+unsigned char *br_ssl_engine_sendrec_buf(
+ const br_ssl_engine_context *cc, size_t *len);
+void br_ssl_engine_sendrec_ack(br_ssl_engine_context *cc, size_t len);
+
+unsigned char *br_ssl_engine_recvrec_buf(
+ const br_ssl_engine_context *cc, size_t *len);
+void br_ssl_engine_recvrec_ack(br_ssl_engine_context *cc, size_t len);
+
+/*
+ * If some application data has been buffered in the engine, then wrap
+ * it into a record and mark it for sending. If no application data has
+ * been buffered but the engine would be ready to accept some, AND the
+ * 'force' parameter is non-zero, then an empty record is assembled and
+ * marked for sending. In all other cases, this function does nothing.
+ *
+ * Empty records are technically legal, but not all existing SSL/TLS
+ * implementations support them. Empty records can be useful as a
+ * transparent "keep-alive" mechanism to maintain some low-level
+ * network activity.
+ */
+void br_ssl_engine_flush(br_ssl_engine_context *cc, int force);
+
+/*
+ * Close the context. If, at that point, the context is open and in
+ * ready state, then a close_notify alert is assembled and marked for
+ * sending. Otherwise, no such alert is assembled.
+ */
+void br_ssl_engine_close(br_ssl_engine_context *cc);
+
+/*
+ * Initiate a renegotiation. If the engine is failed or closed, or if
+ * the peer is known not to support secure renegotiation (RFC 5746),
+ * then this function returns 0. Otherwise, this function returns 1 and
+ * a renegotiation attempt is triggered, unless a handshake is already
+ * taking place, in which case the call is ignored.
+ */
+int br_ssl_engine_renegotiate(br_ssl_engine_context *cc);
+
+/*
+ * Context structure for a SSL client.
+ */
+typedef struct {
+ /*
+ * The encapsulated engine context.
+ */
+ br_ssl_engine_context eng;
+
+ /*
+ * Implementations.
+ */
+ br_rsa_public irsapub;
+ br_rsa_pkcs1_vrfy irsavrfy;
+ br_ecdsa_vrfy iecdsa;
+
+} br_ssl_client_context;
+
+/*
+ * Each br_ssl_client_init_xxx() function sets the list of supported
+ * cipher suites and used implementations, as specified by the profile
+ * name 'xxx'. Defined profile names are:
+ *
+ * full all supported versions and suites; constant-time implementations
+ * FIXME: add other profiles
+ */
+
+void br_ssl_client_init_full(br_ssl_client_context *cc,
+ br_x509_minimal_context *xc,
+ const br_x509_trust_anchor *trust_anchors, size_t trust_anchors_num);
+
+/*
+ * Clear the complete contents of a SSL client context, including the
+ * reference to the configured buffer, implementations, cipher suites
+ * and state.
+ */
+void br_ssl_client_zero(br_ssl_client_context *cc);
+
+/*
+ * Set the RSA public-key operations implementation. This will be used
+ * to encrypt the pre-master secret with the server's RSA public key
+ * (RSA-encryption cipher suites only).
+ */
+static inline void
+br_ssl_client_set_rsapub(br_ssl_client_context *cc, br_rsa_public irsapub)
+{
+ cc->irsapub = irsapub;
+}
+
+/*
+ * Set the RSA signature verification implementation. This will be used
+ * to verify the server's signature on its ServerKeyExchange message
+ * (ECDHE_RSA cipher suites only).
+ */
+static inline void
+br_ssl_client_set_rsavrfy(br_ssl_client_context *cc, br_rsa_pkcs1_vrfy irsavrfy)
+{
+ cc->irsavrfy = irsavrfy;
+}
+
+/*
+ * Set the ECDSA implementation (signature verification). The ECC core
+ * implementation must also have been set.
+ */
+static inline void
+br_ssl_client_set_ecdsa(br_ssl_client_context *cc, br_ecdsa_vrfy iecdsa)
+{
+ cc->iecdsa = iecdsa;
+}
+
+/*
+ * Prepare or reset a client context for connecting with a server of
+ * name 'server_name'. The 'server_name' parameter is used to fill the
+ * SNI extension; if the parameter is NULL then no SNI extension will
+ * be sent.
+ *
+ * If 'resume_session' is non-zero and the context was previously used
+ * then the session parameters may be reused (depending on whether the
+ * server previously sent a non-empty session ID, and accepts the session
+ * resumption).
+ *
+ * On failure, the context is marked as failed, and this function
+ * returns 0. A possible failure condition is when no initial entropy
+ * was injected, and none could be obtained from the OS (either OS
+ * randomness gathering is not supported, or it failed).
+ */
+int br_ssl_client_reset(br_ssl_client_context *cc,
+ const char *server_name, int resume_session);
+
+/*
+ * Forget any session in the context. This means that the next handshake
+ * that uses this context will necessarily be a full handshake (this
+ * applies both to new connections and to renegotiations).
+ */
+static inline void
+br_ssl_client_forget_session(br_ssl_client_context *cc)
+{
+ cc->eng.session.session_id_len = 0;
+}
+
+/*
+ * Type for a "translated cipher suite", as an array of 16-bit integers:
+ * first element is the cipher suite identifier (as used on the wire),
+ * and the second element is the concatenation of four 4-bit elements which
+ * characterise the cipher suite contents. In most to least significant
+ * order, these 4-bit elements are:
+ *
+ * Bits 12 to 15: key exchange + server key type
+ * 0 RSA RSA key exchange, key is RSA (encryption)
+ * 1 ECDHE-RSA ECDHE key exchange, key is RSA (signature)
+ * 2 ECDHE-ECDSA ECDHE key exchange, key is EC (signature)
+ * 3 ECDH-RSA Key is EC (key exchange), cert is signed with RSA
+ * 4 ECDH-ECDSA Key is EC (key exchange), cert is signed with ECDSA
+ *
+ * Bits 8 to 11: symmetric encryption algorithm
+ * 0 3DES/CBC
+ * 1 AES-128/CBC
+ * 2 AES-256/CBC
+ * 3 AES-128/GCM
+ * 4 AES-256/GCM
+ * 5 ChaCha20/Poly1305
+ *
+ * Bits 4 to 7: MAC algorithm
+ * 0 AEAD No dedicated MAC because encryption is AEAD
+ * 2 HMAC/SHA-1 Value matches br_sha1_ID
+ * 4 HMAC/SHA-256 Value matches br_sha256_ID
+ * 5 HMAC/SHA-384 Value matches br_sha384_ID
+ *
+ * Bits 0 to 3: hash function for PRF when used with TLS-1.2
+ * 4 SHA-256 Value matches br_sha256_ID
+ * 5 SHA-384 Value matches br_sha384_ID
+ */
+typedef uint16_t br_suite_translated[2];
+
+#define BR_SSLKEYX_RSA 0
+#define BR_SSLKEYX_ECDHE_RSA 1
+#define BR_SSLKEYX_ECDHE_ECDSA 2
+#define BR_SSLKEYX_ECDH_RSA 3
+#define BR_SSLKEYX_ECDH_ECDSA 4
+
+#define BR_SSLENC_3DES_CBC 0
+#define BR_SSLENC_AES128_CBC 1
+#define BR_SSLENC_AES256_CBC 2
+#define BR_SSLENC_AES128_GCM 3
+#define BR_SSLENC_AES256_GCM 4
+#define BR_SSLENC_CHACHA20 5
+
+#define BR_SSLMAC_AEAD 0
+#define BR_SSLMAC_SHA1 br_sha1_ID
+#define BR_SSLMAC_SHA256 br_sha256_ID
+#define BR_SSLMAC_SHA384 br_sha384_ID
+
+#define BR_SSLPRF_SHA256 br_sha256_ID
+#define BR_SSLPRF_SHA384 br_sha384_ID
+
+/*
+ * Pre-declaration for the SSL server context.
+ */
+typedef struct br_ssl_server_context_ br_ssl_server_context;
+
+/*
+ * Type for the server policy choices, taken after analysis of the client
+ * message:
+ *
+ * cipher_suite Cipher suite to use.
+ *
+ * hash_id Signature hash function identifier (hash function
+ * to use for signing the ServerKeyExchange, when the
+ * suite uses ECDHE).
+ *
+ * chain The certificate chain to send (number of certificates
+ * chain_len is in chain_length). The certificates are send "as is"
+ * and shall be in standard SSL/TLS order (i.e. end-entity
+ * first, each subsequent certificate signs the previous).
+ */
+typedef struct {
+ uint16_t cipher_suite;
+ int hash_id;
+ const br_x509_certificate *chain;
+ size_t chain_len;
+} br_ssl_server_choices;
+
+/*
+ * Type for the certificate and private key handler on the server: an
+ * object with the following methods:
+ *
+ * choose Select the parameters for this connection (cipher suite,
+ * certificate chain...). The selection is written into the
+ * '*choices' structure. Returned value is 1 on success, or
+ * 0 on error (an error here means that the handshake will
+ * fail, and a handshake_failure alert will be sent to the
+ * client).
+ *
+ * do_keyx Perform the server-side key exchange operation. Returned
+ * value is 1 on success, 0 on error (see below). This is
+ * called only when the selected cipher suite calls for a
+ * RSA or ECDH key exchange involving the server key.
+ *
+ * do_sign Perform the server-side signature operation. Returned
+ * value is the signature length, or 0 on error (see below).
+ * This is called only when the selected cipher suite calls
+ * for an ECDHE key exchange, signed by the server with its key.
+ *
+ *
+ * The do_keyx() method shall apply the following semantics:
+ *
+ * -- For RSA key exchange, it shall decrypt the incoming data along
+ * the rules of PKCS#1 v1.5. The method must verify the proper padding
+ * and also that the decrypted message length is exactly 48 bytes.
+ * IMPORTANT: these operations MUST be constant-time (or adequatly blinded).
+ * The decrypted message is written in the first 48 bytes of data[]. The
+ * caller makes sure that the data[] buffer is large enough, and that 'len'
+ * is at least 59 bytes.
+ *
+ * -- For ECDH key exchange, the provided data is an EC point (uncompressed
+ * format); the method shall multiply that point with the server private
+ * key, and write the X coordinate of the resulting point in the data[]
+ * buffer, starting at offset 1 (so if the method produces a compressed or
+ * uncompressed point, form offset 0, then everything is fine).
+ *
+ * In both cases, returned value is 1 on success, 0 on error.
+ *
+ *
+ * The do_sign() method shall compute the signature on the hash value
+ * provided in the data[] buffer. The 'hv_len' value contains the hash
+ * value length, while the 'len' parameter is the total size of the
+ * buffer. The method must verify that the signature length is no more
+ * than 'len' bytes, and report an error otherwise.
+ *
+ * The hash identifier is either 0 for the MD5+SHA-1 method in TLS-1.0 and
+ * 1.1, or a non-zero hash function identifier in TLS-1.2 and later. In
+ * the MD5+SHA-1 method, the hash value has length 36 bytes and there is
+ * no hash function identifying header to add in the padding.
+ *
+ * Returned value is the signature length (in bytes). On error, this method
+ * shall return 0.
+ */
+typedef struct br_ssl_server_policy_class_ br_ssl_server_policy_class;
+struct br_ssl_server_policy_class_ {
+ size_t context_size;
+ int (*choose)(const br_ssl_server_policy_class **pctx,
+ const br_ssl_server_context *cc,
+ br_ssl_server_choices *choices);
+ uint32_t (*do_keyx)(const br_ssl_server_policy_class **pctx,
+ unsigned char *data, size_t len);
+ size_t (*do_sign)(const br_ssl_server_policy_class **pctx,
+ int hash_id, size_t hv_len, unsigned char *data, size_t len);
+};
+
+/*
+ * A single-chain RSA policy handler, that always uses a single chain and
+ * a RSA key. It may be restricted to do only signatures or only key
+ * exchange.
+ */
+typedef struct {
+ const br_ssl_server_policy_class *vtable;
+ const br_x509_certificate *chain;
+ size_t chain_len;
+ const br_rsa_private_key *sk;
+ unsigned allowed_usages;
+ br_rsa_private irsacore;
+ br_rsa_pkcs1_sign irsasign;
+} br_ssl_server_policy_rsa_context;
+
+/*
+ * A single-chain EC policy handler, that always uses a single chain and
+ * an EC key. It may be restricted to do only signatures or only key
+ * exchange.
+ */
+typedef struct {
+ const br_ssl_server_policy_class *vtable;
+ const br_x509_certificate *chain;
+ size_t chain_len;
+ const br_ec_private_key *sk;
+ unsigned allowed_usages;
+ unsigned cert_issuer_key_type;
+ const br_multihash_context *mhash;
+ const br_ec_impl *iec;
+ br_ecdsa_sign iecdsa;
+} br_ssl_server_policy_ec_context;
+
+/*
+ * Class type for a session parameter cache.
+ *
+ * save Record session parameters. The session ID has been randomly
+ * generated, and the session ID length is always 32 bytes.
+ * The method shall copy the provided information (the structure
+ * is transient).
+ *
+ * load Find session parameters by ID. The session ID is in the relevant
+ * field in the '*params' structure, and has always length exactly
+ * 32 bytes. The method shall fill in the other field with the
+ * session data, if found. Returned value is 1 when the session was
+ * found, 0 otherwise.
+ *
+ * Note that the requesting server context is provided. Implementations
+ * may used some of the resources of that context, e.g. random number
+ * generator or implementations of some cryptographic algorithms.
+ */
+typedef struct br_ssl_session_cache_class_ br_ssl_session_cache_class;
+struct br_ssl_session_cache_class_ {
+ size_t context_size;
+ void (*save)(const br_ssl_session_cache_class **ctx,
+ br_ssl_server_context *server_ctx,
+ const br_ssl_session_parameters *params);
+ int (*load)(const br_ssl_session_cache_class **ctx,
+ br_ssl_server_context *server_ctx,
+ br_ssl_session_parameters *params);
+};
+
+/*
+ * Context for a very basic cache system that uses a linked list, managed
+ * with an LRU algorithm (when the cache is full and a new set of parameters
+ * must be saved, the least recently used entry is evicted). The storage
+ * buffer is externally provided. Internally, an index tree is used to
+ * speed up operations.
+ */
+typedef struct {
+ const br_ssl_session_cache_class *vtable;
+ unsigned char *store;
+ size_t store_len, store_ptr;
+ unsigned char index_key[32];
+ const br_hash_class *hash;
+ int init_done;
+ uint32_t head, tail, root;
+} br_ssl_session_cache_lru;
+
+/*
+ * Initialise a LRU session cache with the provided storage space.
+ */
+void br_ssl_session_cache_lru_init(br_ssl_session_cache_lru *cc,
+ unsigned char *store, size_t store_len);
+
+/*
+ * Context structure for a SSL server.
+ */
+struct br_ssl_server_context_ {
+ /*
+ * The encapsulated engine context.
+ */
+ br_ssl_engine_context eng;
+
+ /*
+ * Flags.
+ */
+ uint32_t flags;
+
+ /*
+ * Maximum version from the client.
+ */
+ uint16_t client_max_version;
+
+ /*
+ * Session cache.
+ */
+ const br_ssl_session_cache_class **cache_vtable;
+
+ /*
+ * Translated cipher suites supported by the client. The list
+ * is trimmed to include only the cipher suites that the
+ * server also supports; they are in the same order as in the
+ * client message.
+ */
+ br_suite_translated client_suites[BR_MAX_CIPHER_SUITES];
+ unsigned char client_suites_num;
+
+ /*
+ * Hash functions supported by the client, with ECDSA and RSA
+ * (bit mask). For hash function with id 'x', set bit index is
+ * x for RSA, x+8 for ECDSA.
+ */
+ uint16_t hashes;
+
+ /*
+ * Curves supported by the client (bit mask, for named curves).
+ */
+ uint32_t curves;
+
+ /*
+ * Context for chain handler.
+ */
+ const br_ssl_server_policy_class **policy_vtable;
+ const br_x509_certificate *chain;
+ size_t chain_len;
+ const unsigned char *cert_cur;
+ size_t cert_len;
+ unsigned char sign_hash_id;
+
+ /*
+ * For the core handlers, thus avoiding (in most cases) the
+ * need for an externally provided policy context.
+ */
+ union {
+ const br_ssl_server_policy_class *vtable;
+ br_ssl_server_policy_rsa_context single_rsa;
+ br_ssl_server_policy_ec_context single_ec;
+ } chain_handler;
+
+ /*
+ * Buffer for the ECDHE private key.
+ */
+ unsigned char ecdhe_key[70];
+ size_t ecdhe_key_len;
+
+ /*
+ * Server-specific implementations.
+ */
+};
+
+/*
+ * Get currently defined server behavioural flags.
+ */
+static inline uint32_t
+br_ssl_server_get_flags(br_ssl_server_context *cc)
+{
+ return cc->flags;
+}
+
+/*
+ * Set all server flags. Flags which are not in the 'flags' argument
+ * are cleared.
+ */
+static inline void
+br_ssl_server_set_all_flags(br_ssl_server_context *cc, uint32_t flags)
+{
+ cc->flags = flags;
+}
+
+/*
+ * Add some server flags. The provided flags are set in the server context,
+ * but other flags are untouched.
+ */
+static inline void
+br_ssl_server_add_flags(br_ssl_server_context *cc, uint32_t flags)
+{
+ cc->flags |= flags;
+}
+
+/*
+ * Remove some server flags. The provided flags are cleared from the
+ * server context, but other flags are untouched.
+ */
+static inline void
+br_ssl_server_remove_flags(br_ssl_server_context *cc, uint32_t flags)
+{
+ cc->flags &= ~flags;
+}
+
+/*
+ * If this flag is set, then the server will enforce its own cipher suite
+ * preference order; otherwise, it follows the client preferences.
+ */
+#define BR_OPT_ENFORCE_SERVER_PREFERENCES ((uint32_t)1 << 0)
+
+/*
+ * Each br_ssl_server_init_xxx() function sets the list of supported
+ * cipher suites and used implementations, as specified by the profile
+ * name 'xxx'. Defined profile names are:
+ *
+ * full_rsa all supported algorithm, server key type is RSA
+ * full_ec all supported algorithm, server key type is EC
+ * FIXME: add other profiles
+ *
+ * Naming scheme for "minimal" profiles: min123
+ *
+ * -- character 1: key exchange
+ * r = RSA
+ * e = ECDHE_RSA
+ * f = ECDHE_ECDSA
+ * u = ECDH_RSA
+ * v = ECDH_ECDSA
+ * -- character 2: version / PRF
+ * 0 = TLS 1.0 / 1.1 with MD5+SHA-1
+ * 2 = TLS 1.2 with SHA-256
+ * 3 = TLS 1.2 with SHA-384
+ * -- character 3: encryption
+ * a = AES/CBC
+ * g = AES/GCM
+ * d = 3DES/CBC
+ */
+
+void br_ssl_server_init_full_rsa(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_rsa_private_key *sk);
+
+void br_ssl_server_init_full_ec(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ unsigned cert_issuer_key_type, const br_ec_private_key *sk);
+
+void br_ssl_server_init_minr2g(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_rsa_private_key *sk);
+void br_ssl_server_init_mine2g(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_rsa_private_key *sk);
+void br_ssl_server_init_minf2g(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_ec_private_key *sk);
+void br_ssl_server_init_minu2g(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_ec_private_key *sk);
+void br_ssl_server_init_minv2g(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_ec_private_key *sk);
+
+/*
+ * Get the supported client suites. The returned array is ordered by
+ * client or server preferences, depending on the relevant flag.
+ */
+static inline const br_suite_translated *
+br_ssl_server_get_client_suites(const br_ssl_server_context *cc, size_t *num)
+{
+ *num = cc->client_suites_num;
+ return cc->client_suites;
+}
+
+/*
+ * Get the hash functions supported by the client. This is a field of
+ * bits: for hash function of ID x, bit x is set if the hash function
+ * is supported in RSA signatures, 8+x if it is supported with ECDSA.
+ */
+static inline uint16_t
+br_ssl_server_get_client_hashes(const br_ssl_server_context *cc)
+{
+ return cc->hashes;
+}
+
+/*
+ * Get the elliptic curves supported by the client. This is a bit field
+ * (bit x is set if curve of ID x is supported).
+ */
+static inline uint32_t
+br_ssl_server_get_client_curves(const br_ssl_server_context *cc)
+{
+ return cc->curves;
+}
+
+/*
+ * Clear the complete contents of a SSL server context, including the
+ * reference to the configured buffer, implementations, cipher suites
+ * and state.
+ */
+void br_ssl_server_zero(br_ssl_server_context *cc);
+
+/*
+ * Set an externally provided policy context.
+ */
+static inline void
+br_ssl_server_set_policy(br_ssl_server_context *cc,
+ const br_ssl_server_policy_class **pctx)
+{
+ cc->policy_vtable = pctx;
+}
+
+/*
+ * Set the server certificate chain and key (single RSA case).
+ * The 'allowed_usages' is a combination of usages, namely
+ * BR_KEYTYPE_KEYX and/or BR_KEYTYPE_SIGN.
+ */
+void br_ssl_server_set_single_rsa(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_length,
+ const br_rsa_private_key *sk, unsigned allowed_usages,
+ br_rsa_private irsacore, br_rsa_pkcs1_sign irsasign);
+
+/*
+ * Set the server certificate chain and key (single EC case).
+ * The 'allowed_usages' is a combination of usages, namely
+ * BR_KEYTYPE_KEYX and/or BR_KEYTYPE_SIGN.
+ */
+void br_ssl_server_set_single_ec(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_length,
+ const br_ec_private_key *sk, unsigned allowed_usages,
+ unsigned cert_issuer_key_type,
+ const br_ec_impl *iec, br_ecdsa_sign iecdsa);
+
+/*
+ * Configure the server context to use the provided cache for session
+ * parameters.
+ */
+static inline void
+br_ssl_server_set_cache(br_ssl_server_context *cc,
+ const br_ssl_session_cache_class **vtable)
+{
+ cc->cache_vtable = vtable;
+}
+
+/*
+ * Prepare or reset a server context for handling an incoming client.
+ */
+int br_ssl_server_reset(br_ssl_server_context *cc);
+
+/* ===================================================================== */
+
+/*
+ * Context for the simplified I/O context. The transport medium is accessed
+ * through the low_read() and low_write() callback functions, each with
+ * its own opaque context pointer.
+ *
+ * low_read() read some bytes, at most 'len' bytes, into data[]. The
+ * returned value is the number of read bytes, or -1 on error.
+ * The 'len' parameter is guaranteed never to exceed 20000,
+ * so the length always fits in an 'int' on all platforms.
+ *
+ * low_write() write up to 'len' bytes, to be read from data[]. The
+ * returned value is the number of written bytes, or -1 on
+ * error. The 'len' parameter is guaranteed never to exceed
+ * 20000, so the length always fits in an 'int' on all
+ * parameters.
+ *
+ * A socket closure (if the transport medium is a socket) should be reported
+ * as an error (-1). The callbacks shall endeavour to block until at least
+ * one byte can be read or written; a callback returning 0 at times is
+ * acceptable, but this normally leads to the callback being immediately
+ * called again, so the callback should at least always try to block for
+ * some time if no I/O can take place.
+ *
+ * The SSL engine naturally applies some buffering, so the callbacks need
+ * not apply buffers of their own.
+ */
+typedef struct {
+ br_ssl_engine_context *engine;
+ int (*low_read)(void *read_context,
+ unsigned char *data, size_t len);
+ void *read_context;
+ int (*low_write)(void *write_context,
+ const unsigned char *data, size_t len);
+ void *write_context;
+} br_sslio_context;
+
+/*
+ * Initialise a simplified I/O context over the provided engine and
+ * I/O callbacks.
+ */
+void br_sslio_init(br_sslio_context *ctx,
+ br_ssl_engine_context *engine,
+ int (*low_read)(void *read_context,
+ unsigned char *data, size_t len),
+ void *read_context,
+ int (*low_write)(void *write_context,
+ const unsigned char *data, size_t len),
+ void *write_context);
+
+/*
+ * Read some application data from a SSL connection. This call returns
+ * only when at least one byte has been obtained. Returned value is
+ * the number of bytes read, or -1 on error. The number of bytes
+ * always fits on an 'int' (data from a single SSL/TLS record is
+ * returned).
+ *
+ * On error or SSL closure, this function returns -1. The caller should
+ * inspect the error status on the SSL engine to distinguish between
+ * normal closure and error.
+ */
+int br_sslio_read(br_sslio_context *cc, void *dst, size_t len);
+
+/*
+ * Read some application data from a SSL connection. This call returns
+ * only when ALL requested bytes have been read. Returned value is 0
+ * on success, -1 on error. A normal SSL closure before that many bytes
+ * are obtained is reported as an error by this function.
+ */
+int br_sslio_read_all(br_sslio_context *cc, void *dst, size_t len);
+
+/*
+ * Write some application data onto a SSL connection. This call returns
+ * only when at least one byte had been written onto the connection (but
+ * not necessarily flushed). Returned value is the number of written
+ * bytes, or -1 on error (error conditions include a closed connection).
+ * It is guaranteed that the number of bytes written by such a call will
+ * fit in an 'int' on all architectures.
+ *
+ * Note that some written bytes may be buffered; use br_sslio_flush()
+ * to make sure that the data is sent to the transport stream.
+ */
+int br_sslio_write(br_sslio_context *cc, const void *src, size_t len);
+
+/*
+ * Write some application data onto a SSL connection. This call returns
+ * only when ALL the bytes have been written onto the connection (but
+ * not necessarily flushed). Returned value is 0 on success, -1 on error.
+ *
+ * Note that some written bytes may be buffered; use br_sslio_flush()
+ * to make sure that the data is sent to the transport stream.
+ */
+int br_sslio_write_all(br_sslio_context *cc, const void *src, size_t len);
+
+/*
+ * Make sure that any buffered application data in the provided context
+ * get packed up and sent unto the low_write() callback method. If that
+ * callback method represents a buffered system, it is up to the caller
+ * to then "flush" that system too.
+ *
+ * Returned value is 0 on success, -1 on error.
+ */
+int br_sslio_flush(br_sslio_context *cc);
+
+/*
+ * Perform a SSL close. This implies sending a close_notify, and reading
+ * the response from the server. Returned value is 0 on success, -1 on
+ * error.
+ */
+int br_sslio_close(br_sslio_context *cc);
+
+/* ===================================================================== */
+
+/*
+ * Symbolic constants for cipher suites.
+ */
+
+/* From RFC 5246 */
+#define BR_TLS_NULL_WITH_NULL_NULL 0x0000
+#define BR_TLS_RSA_WITH_NULL_MD5 0x0001
+#define BR_TLS_RSA_WITH_NULL_SHA 0x0002
+#define BR_TLS_RSA_WITH_NULL_SHA256 0x003B
+#define BR_TLS_RSA_WITH_RC4_128_MD5 0x0004
+#define BR_TLS_RSA_WITH_RC4_128_SHA 0x0005
+#define BR_TLS_RSA_WITH_3DES_EDE_CBC_SHA 0x000A
+#define BR_TLS_RSA_WITH_AES_128_CBC_SHA 0x002F
+#define BR_TLS_RSA_WITH_AES_256_CBC_SHA 0x0035
+#define BR_TLS_RSA_WITH_AES_128_CBC_SHA256 0x003C
+#define BR_TLS_RSA_WITH_AES_256_CBC_SHA256 0x003D
+#define BR_TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA 0x000D
+#define BR_TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA 0x0010
+#define BR_TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA 0x0013
+#define BR_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA 0x0016
+#define BR_TLS_DH_DSS_WITH_AES_128_CBC_SHA 0x0030
+#define BR_TLS_DH_RSA_WITH_AES_128_CBC_SHA 0x0031
+#define BR_TLS_DHE_DSS_WITH_AES_128_CBC_SHA 0x0032
+#define BR_TLS_DHE_RSA_WITH_AES_128_CBC_SHA 0x0033
+#define BR_TLS_DH_DSS_WITH_AES_256_CBC_SHA 0x0036
+#define BR_TLS_DH_RSA_WITH_AES_256_CBC_SHA 0x0037
+#define BR_TLS_DHE_DSS_WITH_AES_256_CBC_SHA 0x0038
+#define BR_TLS_DHE_RSA_WITH_AES_256_CBC_SHA 0x0039
+#define BR_TLS_DH_DSS_WITH_AES_128_CBC_SHA256 0x003E
+#define BR_TLS_DH_RSA_WITH_AES_128_CBC_SHA256 0x003F
+#define BR_TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 0x0040
+#define BR_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 0x0067
+#define BR_TLS_DH_DSS_WITH_AES_256_CBC_SHA256 0x0068
+#define BR_TLS_DH_RSA_WITH_AES_256_CBC_SHA256 0x0069
+#define BR_TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 0x006A
+#define BR_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 0x006B
+#define BR_TLS_DH_anon_WITH_RC4_128_MD5 0x0018
+#define BR_TLS_DH_anon_WITH_3DES_EDE_CBC_SHA 0x001B
+#define BR_TLS_DH_anon_WITH_AES_128_CBC_SHA 0x0034
+#define BR_TLS_DH_anon_WITH_AES_256_CBC_SHA 0x003A
+#define BR_TLS_DH_anon_WITH_AES_128_CBC_SHA256 0x006C
+#define BR_TLS_DH_anon_WITH_AES_256_CBC_SHA256 0x006D
+
+/* From RFC 4492 */
+#define BR_TLS_ECDH_ECDSA_WITH_NULL_SHA 0xC001
+#define BR_TLS_ECDH_ECDSA_WITH_RC4_128_SHA 0xC002
+#define BR_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA 0xC003
+#define BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA 0xC004
+#define BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA 0xC005
+#define BR_TLS_ECDHE_ECDSA_WITH_NULL_SHA 0xC006
+#define BR_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA 0xC007
+#define BR_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA 0xC008
+#define BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA 0xC009
+#define BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA 0xC00A
+#define BR_TLS_ECDH_RSA_WITH_NULL_SHA 0xC00B
+#define BR_TLS_ECDH_RSA_WITH_RC4_128_SHA 0xC00C
+#define BR_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA 0xC00D
+#define BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA 0xC00E
+#define BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA 0xC00F
+#define BR_TLS_ECDHE_RSA_WITH_NULL_SHA 0xC010
+#define BR_TLS_ECDHE_RSA_WITH_RC4_128_SHA 0xC011
+#define BR_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA 0xC012
+#define BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA 0xC013
+#define BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA 0xC014
+#define BR_TLS_ECDH_anon_WITH_NULL_SHA 0xC015
+#define BR_TLS_ECDH_anon_WITH_RC4_128_SHA 0xC016
+#define BR_TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA 0xC017
+#define BR_TLS_ECDH_anon_WITH_AES_128_CBC_SHA 0xC018
+#define BR_TLS_ECDH_anon_WITH_AES_256_CBC_SHA 0xC019
+
+/* From RFC 5288 */
+#define BR_TLS_RSA_WITH_AES_128_GCM_SHA256 0x009C
+#define BR_TLS_RSA_WITH_AES_256_GCM_SHA384 0x009D
+#define BR_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 0x009E
+#define BR_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 0x009F
+#define BR_TLS_DH_RSA_WITH_AES_128_GCM_SHA256 0x00A0
+#define BR_TLS_DH_RSA_WITH_AES_256_GCM_SHA384 0x00A1
+#define BR_TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 0x00A2
+#define BR_TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 0x00A3
+#define BR_TLS_DH_DSS_WITH_AES_128_GCM_SHA256 0x00A4
+#define BR_TLS_DH_DSS_WITH_AES_256_GCM_SHA384 0x00A5
+#define BR_TLS_DH_anon_WITH_AES_128_GCM_SHA256 0x00A6
+#define BR_TLS_DH_anon_WITH_AES_256_GCM_SHA384 0x00A7
+
+/* From RFC 5289 */
+#define BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 0xC023
+#define BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 0xC024
+#define BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 0xC025
+#define BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 0xC026
+#define BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 0xC027
+#define BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 0xC028
+#define BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 0xC029
+#define BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 0xC02A
+#define BR_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 0xC02B
+#define BR_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 0xC02C
+#define BR_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 0xC02D
+#define BR_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 0xC02E
+#define BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 0xC02F
+#define BR_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 0xC030
+#define BR_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 0xC031
+#define BR_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 0xC032
+
+/* From RFC 7905 */
+#define BR_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 0xCCA8
+#define BR_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 0xCCA9
+#define BR_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 0xCCAA
+#define BR_TLS_PSK_WITH_CHACHA20_POLY1305_SHA256 0xCCAB
+#define BR_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 0xCCAC
+#define BR_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 0xCCAD
+#define BR_TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256 0xCCAE
+
+/*
+ * Symbolic constants for alerts.
+ */
+#define BR_ALERT_CLOSE_NOTIFY 0
+#define BR_ALERT_UNEXPECTED_MESSAGE 10
+#define BR_ALERT_BAD_RECORD_MAC 20
+#define BR_ALERT_RECORD_OVERFLOW 22
+#define BR_ALERT_DECOMPRESSION_FAILURE 30
+#define BR_ALERT_HANDSHAKE_FAILURE 40
+#define BR_ALERT_BAD_CERTIFICATE 42
+#define BR_ALERT_UNSUPPORTED_CERTIFICATE 43
+#define BR_ALERT_CERTIFICATE_REVOKED 44
+#define BR_ALERT_CERTIFICATE_EXPIRED 45
+#define BR_ALERT_CERTIFICATE_UNKNOWN 46
+#define BR_ALERT_ILLEGAL_PARAMETER 47
+#define BR_ALERT_UNKNOWN_CA 48
+#define BR_ALERT_ACCESS_DENIED 49
+#define BR_ALERT_DECODE_ERROR 50
+#define BR_ALERT_DECRYPT_ERROR 51
+#define BR_ALERT_PROTOCOL_VERSION 70
+#define BR_ALERT_INSUFFICIENT_SECURITY 71
+#define BR_ALERT_INTERNAL_ERROR 80
+#define BR_ALERT_USER_CANCELED 90
+#define BR_ALERT_NO_RENEGOTIATION 100
+#define BR_ALERT_UNSUPPORTED_EXTENSION 110
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+#ifndef BR_BEARSSL_X509_H__
+#define BR_BEARSSL_X509_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "bearssl_ec.h"
+#include "bearssl_hash.h"
+#include "bearssl_rsa.h"
+
+/*
+ * X.509 Certificate Chain Processing
+ * ----------------------------------
+ *
+ * An X.509 processing engine receives an X.509 chain, chunk by chunk,
+ * as received from a SSL/TLS client or server (the client receives the
+ * server's certificate chain, and the server receives the client's
+ * certificate chain if it requested a client certificate). The chain
+ * is thus injected in the engine in SSL order (end-entity first).
+ *
+ * The engine's job is to return the public key to use for SSL/TLS.
+ * How exactly that key is obtained and verified is entirely up to the
+ * engine.
+ */
+
+/*
+ * X.509 error codes are in the 32..63 range.
+ */
+
+/* Validation was successful; this is not actually an error. */
+#define BR_ERR_X509_OK 32
+
+/* Invalid value in an ASN.1 structure. */
+#define BR_ERR_X509_INVALID_VALUE 33
+
+/* Truncated certificate. */
+#define BR_ERR_X509_TRUNCATED 34
+
+/* Empty certificate chain (no certificate at all). */
+#define BR_ERR_X509_EMPTY_CHAIN 35
+
+/* Decoding error: inner element extends beyond outer element size. */
+#define BR_ERR_X509_INNER_TRUNC 36
+
+/* Decoding error: unsupported tag class (application or private). */
+#define BR_ERR_X509_BAD_TAG_CLASS 37
+
+/* Decoding error: unsupported tag value. */
+#define BR_ERR_X509_BAD_TAG_VALUE 38
+
+/* Decoding error: indefinite length. */
+#define BR_ERR_X509_INDEFINITE_LENGTH 39
+
+/* Decoding error: extraneous element. */
+#define BR_ERR_X509_EXTRA_ELEMENT 40
+
+/* Decoding error: unexpected element. */
+#define BR_ERR_X509_UNEXPECTED 41
+
+/* Decoding error: expected constructed element, but is primitive. */
+#define BR_ERR_X509_NOT_CONSTRUCTED 42
+
+/* Decoding error: expected primitive element, but is constructed. */
+#define BR_ERR_X509_NOT_PRIMITIVE 43
+
+/* Decoding error: BIT STRING length is not multiple of 8. */
+#define BR_ERR_X509_PARTIAL_BYTE 44
+
+/* Decoding error: BOOLEAN value has invalid length. */
+#define BR_ERR_X509_BAD_BOOLEAN 45
+
+/* Decoding error: value is off-limits. */
+#define BR_ERR_X509_OVERFLOW 46
+
+/* Invalid distinguished name. */
+#define BR_ERR_X509_BAD_DN 47
+
+/* Invalid date/time representation. */
+#define BR_ERR_X509_BAD_TIME 48
+
+/* Certificate contains unsupported features that cannot be ignored. */
+#define BR_ERR_X509_UNSUPPORTED 49
+
+/* Key or signature size exceeds internal limits. */
+#define BR_ERR_X509_LIMIT_EXCEEDED 50
+
+/* Key type does not match that which was expected. */
+#define BR_ERR_X509_WRONG_KEY_TYPE 51
+
+/* Signature is invalid. */
+#define BR_ERR_X509_BAD_SIGNATURE 52
+
+/* Validation time is unknown. */
+#define BR_ERR_X509_TIME_UNKNOWN 53
+
+/* Certificate is expired or not yet valid. */
+#define BR_ERR_X509_EXPIRED 54
+
+/* Issuer/Subject DN mismatch in the chain. */
+#define BR_ERR_X509_DN_MISMATCH 55
+
+/* Expected server name was not found in the chain. */
+#define BR_ERR_X509_BAD_SERVER_NAME 56
+
+/* Unknown critical extension in certificate. */
+#define BR_ERR_X509_CRITICAL_EXTENSION 57
+
+/* Not a CA, or path length constraint violation */
+#define BR_ERR_X509_NOT_CA 58
+
+/* Key Usage extension prohibits intended usage. */
+#define BR_ERR_X509_FORBIDDEN_KEY_USAGE 59
+
+/* Public key found in certificate is too small. */
+#define BR_ERR_X509_WEAK_PUBLIC_KEY 60
+
+/* Chain could not be linked to a trust anchor. */
+#define BR_ERR_X509_NOT_TRUSTED 62
+
+/*
+ * A structure to encode public keys.
+ */
+typedef struct {
+ unsigned char key_type;
+ union {
+ br_rsa_public_key rsa;
+ br_ec_public_key ec;
+ } key;
+} br_x509_pkey;
+
+/*
+ * A trust anchor consists in:
+ * -- an encoded DN
+ * -- a public key
+ * -- flags
+ */
+typedef struct {
+ unsigned char *dn;
+ size_t dn_len;
+ /* unsigned char hashed_DN[64]; */
+ unsigned flags;
+ br_x509_pkey pkey;
+} br_x509_trust_anchor;
+
+/* Trust anchor flag: trust anchor is a CA and thus acceptable for
+ signing other certificates. Without this flag, the trust anchor
+ is only for direct trust (name and key match EE certificate). */
+#define BR_X509_TA_CA 0x0001
+
+/*
+ * Key type: combination of a basic key type (low 4 bits) and some
+ * optional flags.
+ *
+ * For a public key, the basic key type only is set.
+ *
+ * For an expected key type, the flags indicate the intended purpose(s)
+ * for the key; the basic key type may be set to 0 to indicate that any
+ * key type compatible with the indicated purpose is acceptable.
+ */
+#define BR_KEYTYPE_RSA 1
+#define BR_KEYTYPE_EC 2
+
+#define BR_KEYTYPE_KEYX 0x10 /* key is for key exchange or encryption */
+#define BR_KEYTYPE_SIGN 0x20 /* key is for verifying signatures */
+
+/*
+ * start_chain Called when a new chain is started. If 'server_name'
+ * is not NULL and non-empty, then it is a name that
+ * should be looked for in the EE certificate (in the
+ * SAN extension as dNSName, or in the subjectDN's CN
+ * if there is no SAN extension).
+ * The caller ensures that the provided 'server_name'
+ * pointer remains valid throughout validation.
+ *
+ * start_cert Begins a new certificate in the chain. The provided
+ * length is in bytes; this is the total certificate length.
+ *
+ * append Get some additional bytes for the current certificate.
+ *
+ * end_cert Ends the current certificate.
+ *
+ * end_chain Called at the end of the chain. Returned value is
+ * 0 on success, or a non-zero error code.
+ *
+ * get_pkey Returns the EE certificate public key.
+ *
+ * For a complete chain, start_chain() and end_chain() are always
+ * called. For each certificate, start_cert(), some append() calls, then
+ * end_cert() are called, in that order. There may be no append() call
+ * at all if the certificate is empty (which is not valid but may happen
+ * if the peer sends exactly that).
+ *
+ * get_pkey() shall return a pointer to a structure that is valid as
+ * long as a new chain is not started. This may be a sub-structure
+ * within the context for the engine. This function MAY return a valid
+ * pointer to a public key even in some cases of validation failure,
+ * depending on the validation engine.
+ */
+typedef struct br_x509_class_ br_x509_class;
+struct br_x509_class_ {
+ size_t context_size;
+ void (*start_chain)(const br_x509_class **ctx,
+ unsigned expected_key_type,
+ const char *server_name);
+ void (*start_cert)(const br_x509_class **ctx, uint32_t length);
+ void (*append)(const br_x509_class **ctx,
+ const unsigned char *buf, size_t len);
+ void (*end_cert)(const br_x509_class **ctx);
+ unsigned (*end_chain)(const br_x509_class **ctx);
+ const br_x509_pkey *(*get_pkey)(const br_x509_class *const *ctx);
+};
+
+/*
+ * The "known key" X.509 engine is a trivial engine that completely
+ * ignores the certificates, and instead reports an externally
+ * configured public key.
+ */
+typedef struct {
+ const br_x509_class *vtable;
+ br_x509_pkey pkey;
+} br_x509_knownkey_context;
+extern const br_x509_class br_x509_knownkey_vtable;
+
+/*
+ * Initialize a "known key" X.509 engine with a known RSA public key.
+ * The provided pointers are linked in, not copied, so they must
+ * remain valid while the public key may be in usage (i.e. at least up
+ * to the end of the handshake -- and since there may be renegotiations,
+ * these buffers should stay until the connection is finished).
+ */
+void br_x509_knownkey_init_rsa(br_x509_knownkey_context *ctx,
+ const br_rsa_public_key *pk);
+
+/*
+ * Initialize a "known key" X.509 engine with a known EC public key.
+ * The provided pointers are linked in, not copied, so they must
+ * remain valid while the public key may be in usage (i.e. at least up
+ * to the end of the handshake -- and since there may be renegotiations,
+ * these buffers should stay until the connection is finished).
+ */
+void br_x509_knownkey_init_ec(br_x509_knownkey_context *ctx,
+ const br_ec_public_key *pk);
+
+/*
+ * The minimal X.509 engine has some state buffers which must be large
+ * enough to simultaneously accommodate:
+ * -- the public key extracted from the current certificate;
+ * -- the signature on the current certificate or on the previous
+ * certificate;
+ * -- the public key extracted from the EE certificate.
+ *
+ * We store public key elements in their raw unsigned big-endian
+ * encoding. We want to support up to RSA-4096 with a short (up to 64
+ * bits) public exponent, thus a buffer for a public key must have
+ * length at least 520 bytes. Similarly, a RSA-4096 signature has length
+ * 512 bytes.
+ *
+ * Though RSA public exponents can formally be as large as the modulus
+ * (mathematically, even larger exponents would work, but PKCS#1 forbids
+ * them), exponents that do not fit on 32 bits are extremely rare,
+ * notably because some widespread implementation (e.g. Microsoft's
+ * CryptoAPI) don't support them. Moreover, large public exponent do not
+ * seem to imply any tangible security benefit, and they increase the
+ * cost of public key operations.
+ *
+ * EC public keys are shorter than RSA public keys; even with curve
+ * NIST P-521 (the largest curve we care to support), a public key is
+ * encoded over 133 bytes only.
+ */
+#define BR_X509_BUFSIZE_KEY 520
+#define BR_X509_BUFSIZE_SIG 512
+
+/*
+ * The "minimal" X.509 engine performs basic decoding of certificates and
+ * some validations:
+ * -- DN matching
+ * -- signatures
+ * -- validity dates
+ * -- Basic Constraints extension
+ * -- Server name check against SAN extension
+ */
+typedef struct {
+ const br_x509_class *vtable;
+
+ /* Structure for returning the EE public key. */
+ br_x509_pkey pkey;
+
+ /* CPU for the T0 virtual machine. */
+ struct {
+ uint32_t *dp;
+ uint32_t *rp;
+ const unsigned char *ip;
+ } cpu;
+ uint32_t dp_stack[32];
+ uint32_t rp_stack[32];
+ int err;
+
+ /* Server name to match with the SAN / CN of the EE certificate. */
+ const char *server_name;
+
+ /* Expected EE key type and usage. */
+ unsigned char expected_key_type;
+
+ /* Explicitly set date and time. */
+ uint32_t days, seconds;
+
+ /* Current certificate length (in bytes). Set to 0 when the
+ certificate has been fully processed. */
+ uint32_t cert_length;
+
+ /* Number of certificates processed so far in the current chain.
+ It is incremented at the end of the processing of a certificate,
+ so it is 0 for the EE. */
+ uint32_t num_certs;
+
+ /* Certificate data chunk. */
+ const unsigned char *hbuf;
+ size_t hlen;
+
+ /* The pad serves as destination for various operations. */
+ unsigned char pad[256];
+
+ /* Buffer for EE public key data. */
+ unsigned char ee_pkey_data[BR_X509_BUFSIZE_KEY];
+
+ /* Buffer for currently decoded public key. */
+ unsigned char pkey_data[BR_X509_BUFSIZE_KEY];
+
+ /* Signature type: signer key type, offset to the hash
+ function OID (in the T0 data block) and hash function
+ output length (TBS hash length). */
+ unsigned char cert_signer_key_type;
+ uint16_t cert_sig_hash_oid;
+ unsigned char cert_sig_hash_len;
+
+ /* Current/last certificate signature. */
+ unsigned char cert_sig[BR_X509_BUFSIZE_SIG];
+ uint16_t cert_sig_len;
+
+ /* Minimum RSA key length (difference in bytes from 128). */
+ int16_t min_rsa_size;
+
+ /* Configured trust anchors. */
+ const br_x509_trust_anchor *trust_anchors;
+ size_t trust_anchors_num;
+
+ /*
+ * Multi-hasher for the TBS.
+ */
+ unsigned char do_mhash;
+ br_multihash_context mhash;
+ unsigned char tbs_hash[64];
+
+ /*
+ * Simple hasher for the subject/issuer DN.
+ */
+ unsigned char do_dn_hash;
+ const br_hash_class *dn_hash_impl;
+ br_hash_compat_context dn_hash;
+ unsigned char current_dn_hash[64];
+ unsigned char next_dn_hash[64];
+ unsigned char saved_dn_hash[64];
+
+ /*
+ * Public key cryptography implementations (signature verification).
+ */
+ br_rsa_pkcs1_vrfy irsa;
+ br_ecdsa_vrfy iecdsa;
+ const br_ec_impl *iec;
+
+} br_x509_minimal_context;
+extern const br_x509_class br_x509_minimal_vtable;
+
+/*
+ * Initialize a "minimal" X.509 engine. Parameters are:
+ * -- context to initialize
+ * -- hash function to use for hashing normalized DN
+ * -- list of trust anchors
+ *
+ * After initialization, some hash function implementations for signature
+ * verification MUST be added.
+ */
+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);
+
+/*
+ * Set a hash function implementation, identified by ID, for purposes of
+ * verifying signatures on certificates. This must be called after
+ * br_x509_minimal_init().
+ */
+static inline void
+br_x509_minimal_set_hash(br_x509_minimal_context *ctx,
+ int id, const br_hash_class *impl)
+{
+ br_multihash_setimpl(&ctx->mhash, id, impl);
+}
+
+/*
+ * Set a RSA implementation, for purposes of verifying signatures on
+ * certificates. This must be called after br_x509_minimal_init().
+ */
+static inline void
+br_x509_minimal_set_rsa(br_x509_minimal_context *ctx,
+ br_rsa_pkcs1_vrfy irsa)
+{
+ ctx->irsa = irsa;
+}
+
+/*
+ * Set an ECDSA implementation, for purposes of verifying signatures on
+ * certificates. This must be called after br_x509_minimal_init().
+ */
+static inline void
+br_x509_minimal_set_ecdsa(br_x509_minimal_context *ctx,
+ const br_ec_impl *iec, br_ecdsa_vrfy iecdsa)
+{
+ ctx->iecdsa = iecdsa;
+ ctx->iec = iec;
+}
+
+/*
+ * Set the validation time, normally to the current date and time.
+ * This consists in two 32-bit counts:
+ *
+ * -- Days are counted in a proleptic Gregorian calendar since
+ * January 1st, 0 AD. Year "0 AD" is the one that preceded "1 AD";
+ * it is also traditionally known as "1 BC".
+ *
+ * -- Seconds are counted since midnight, from 0 to 86400 (a count of
+ * 86400 is possible only if a leap second happened).
+ *
+ * If the validation date and time are not explicitly set, but BearSSL
+ * was compiled with support for the system clock on the underlying
+ * platform, then the current time will automatically be used. Otherwise,
+ * validation will fail (except in case of direct trust of the EE key).
+ */
+static inline void
+br_x509_minimal_set_time(br_x509_minimal_context *ctx,
+ uint32_t days, uint32_t seconds)
+{
+ ctx->days = days;
+ ctx->seconds = seconds;
+}
+
+/*
+ * Set the minimal acceptable length for RSA keys, in bytes. Default
+ * is 128 bytes, which means RSA keys of 1017 bits or more. This setting
+ * applies to keys extracted from certificates (EE and intermediate CA).
+ * It does _not_ apply to "CA" trust anchors.
+ */
+static inline void
+br_x509_minimal_set_minrsa(br_x509_minimal_context *ctx, int byte_length)
+{
+ ctx->min_rsa_size = (int16_t)(byte_length - 128);
+}
+
+/*
+ * An X.509 decoder context. This is not for X.509 validation, but for
+ * using certificates as trust anchors (e.g. self-signed certificates
+ * read from files).
+ */
+typedef struct {
+
+ /* Structure for returning the public key. */
+ br_x509_pkey pkey;
+
+ /* CPU for the T0 virtual machine. */
+ struct {
+ uint32_t *dp;
+ uint32_t *rp;
+ const unsigned char *ip;
+ } cpu;
+ uint32_t dp_stack[32];
+ uint32_t rp_stack[32];
+ int err;
+
+ /* The pad serves as destination for various operations. */
+ unsigned char pad[256];
+
+ /* Flag set when decoding succeeds. */
+ unsigned char decoded;
+
+ /* Validity dates. */
+ uint32_t notbefore_days, notbefore_seconds;
+ uint32_t notafter_days, notafter_seconds;
+
+ /* The "CA" flag. This is set to true if the certificate contains
+ a Basic Constraints extension that asserts CA status. */
+ unsigned char isCA;
+
+ /* DN processing: the subject DN is extracted and pushed to the
+ provided callback. */
+ unsigned char copy_dn;
+ void *append_dn_ctx;
+ void (*append_dn)(void *ctx, const void *buf, size_t len);
+
+ /* Certificate data chunk. */
+ const unsigned char *hbuf;
+ size_t hlen;
+
+ /* Buffer for decoded public key. */
+ unsigned char pkey_data[BR_X509_BUFSIZE_KEY];
+
+ /* Type of key and hash function used in the certificate signature. */
+ unsigned char signer_key_type;
+ unsigned char signer_hash_id;
+
+} br_x509_decoder_context;
+
+/*
+ * Initialise an X.509 decoder context for processing a new certificate.
+ */
+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);
+
+/*
+ * Push some certificate bytes into a decoder context.
+ */
+void br_x509_decoder_push(br_x509_decoder_context *ctx,
+ const void *data, size_t len);
+
+/*
+ * Obtain the decoded public key. Returned value is a pointer to a
+ * structure internal to the decoder context; releasing or reusing the
+ * decoder context invalidates that structure.
+ *
+ * If decoding was not finished, or failed, then NULL is returned.
+ */
+static inline br_x509_pkey *
+br_x509_decoder_get_pkey(br_x509_decoder_context *ctx)
+{
+ if (ctx->decoded && ctx->err == 0) {
+ return &ctx->pkey;
+ } else {
+ return NULL;
+ }
+}
+
+/*
+ * Get decoder error. If no error was reported yet but the certificate
+ * decoding is not finished, then the error code is BR_ERR_X509_TRUNCATED.
+ * If decoding was successful, then 0 is returned.
+ */
+static inline int
+br_x509_decoder_last_error(br_x509_decoder_context *ctx)
+{
+ if (ctx->err != 0) {
+ return ctx->err;
+ }
+ if (!ctx->decoded) {
+ return BR_ERR_X509_TRUNCATED;
+ }
+ return 0;
+}
+
+/*
+ * Get the "isCA" flag from an X.509 decoder context. This flag is set
+ * if the decoded certificate claims to be a CA through a Basic
+ * Constraints extension.
+ */
+static inline int
+br_x509_decoder_isCA(br_x509_decoder_context *ctx)
+{
+ return ctx->isCA;
+}
+
+/*
+ * Get the issuing CA key type (type of key used to sign the decoded
+ * certificate). This is BR_KEYTYPE_RSA or BR_KEYTYPE_EC. The value 0
+ * is returned if the signature type was not recognised.
+ */
+static inline int
+br_x509_decoder_get_signer_key_type(br_x509_decoder_context *ctx)
+{
+ return ctx->signer_key_type;
+}
+
+/*
+ * Get the identifier for the hash function used to sign the decoded
+ * certificate. This is 0 if the hash function was not recognised.
+ */
+static inline int
+br_x509_decoder_get_signer_hash_id(br_x509_decoder_context *ctx)
+{
+ return ctx->signer_hash_id;
+}
+
+/*
+ * Type for an X.509 certificate (DER-encoded).
+ */
+typedef struct {
+ unsigned char *data;
+ size_t data_len;
+} br_x509_certificate;
+
+/*
+ * Private key decoder context.
+ */
+typedef struct {
+
+ /* Structure for returning the private key. */
+ union {
+ br_rsa_private_key rsa;
+ br_ec_private_key ec;
+ } key;
+
+ /* CPU for the T0 virtual machine. */
+ struct {
+ uint32_t *dp;
+ uint32_t *rp;
+ const unsigned char *ip;
+ } cpu;
+ uint32_t dp_stack[32];
+ uint32_t rp_stack[32];
+ int err;
+
+ /* Private key data chunk. */
+ const unsigned char *hbuf;
+ size_t hlen;
+
+ /* The pad serves as destination for various operations. */
+ unsigned char pad[256];
+
+ /* Decoded key type; 0 until decoding is complete. */
+ unsigned char key_type;
+
+ /* Buffer for the private key elements. It shall be large enough
+ to accommodate all elements for a RSA-4096 private key (roughly
+ five 2048-bit integers, possibly a bit more). */
+ unsigned char key_data[3 * BR_X509_BUFSIZE_SIG];
+
+} br_skey_decoder_context;
+
+/*
+ * Initialise a private key decoder context.
+ */
+void br_skey_decoder_init(br_skey_decoder_context *ctx);
+
+/*
+ * Push some data bytes into a private key decoder context.
+ */
+void br_skey_decoder_push(br_skey_decoder_context *ctx,
+ const void *data, size_t len);
+
+/*
+ * Get the decoding status for a private key. This is either 0 on success,
+ * or a non-zero error code.
+ */
+static inline int
+br_skey_decoder_last_error(const br_skey_decoder_context *ctx)
+{
+ if (ctx->err != 0) {
+ return ctx->err;
+ }
+ if (ctx->key_type == 0) {
+ return BR_ERR_X509_TRUNCATED;
+ }
+ return 0;
+}
+
+/*
+ * Get the decoded private key type. This is 0 if decoding is not finished
+ * or failed.
+ */
+static inline int
+br_skey_decoder_key_type(const br_skey_decoder_context *ctx)
+{
+ if (ctx->err == 0) {
+ return ctx->key_type;
+ } else {
+ return 0;
+ }
+}
+
+/*
+ * Get the decoded RSA private key. This function returns NULL if the
+ * decoding failed, or is not finished, or the key is not RSA. The returned
+ * pointer references structures within the context that can become
+ * invalid if the context is reused or released.
+ */
+static inline const br_rsa_private_key *
+br_skey_decoder_get_rsa(const br_skey_decoder_context *ctx)
+{
+ if (ctx->err == 0 && ctx->key_type == BR_KEYTYPE_RSA) {
+ return &ctx->key.rsa;
+ } else {
+ return NULL;
+ }
+}
+
+/*
+ * Get the decoded EC private key. This function returns NULL if the
+ * decoding failed, or is not finished, or the key is not EC. The returned
+ * pointer references structures within the context that can become
+ * invalid if the context is reused or released.
+ */
+static inline const br_ec_private_key *
+br_skey_decoder_get_ec(const br_skey_decoder_context *ctx)
+{
+ if (ctx->err == 0 && ctx->key_type == BR_KEYTYPE_EC) {
+ return &ctx->key.ec;
+ } else {
+ return NULL;
+ }
+}
+
+#endif
--- /dev/null
+#! /bin/sh
+
+CSC=$(which mono-csc || which dmcs || echo "none")
+
+if [ $CSC = "none" ]; then
+ echo "Error: Please install mono-devel."
+ exit 1
+fi
+
+set -e
+$CSC /out:T0Comp.exe /main:T0Comp /res:T0/kern.t0,t0-kernel T0/*.cs
--- /dev/null
+This directory contains sample code for using BearSSL.
+
+client_basic.c
+
+ A sample client code, that connects to a server, performs a SSL
+ handshake, sends a basic HTTP GET request, and dumps the complete
+ answer on stdout.
+
+ Compile it against BearSSL headers (in the ../inc directory) and
+ library (libbearssl.a). This code will validate the server
+ certificate against two hardcoded trust anchors.
+
+server_basic.c
+
+ A sample SSL server, that serves one client at a time. It reads a
+ single HTTP request (that it does not really parse; it just waits for
+ the two successive line endings that mark the end of the request),
+ and pushes a basic response.
+
+ Compile it against BearSSL headers (in the ../inc directory) and
+ library (libbearssl.a). Depending on compilation options (see the
+ code), it will use one of several certificate chains, that exercise
+ various combinations of RSA and EC keys and signatures. These
+ certificate chains link to the trust anchors that are hardcoded
+ in client_basic.c, so the sample client and the sample server can
+ be tested against each other.
+
+custom_profile.c
+
+ A sample C source file that shows how to write your own client or
+ server profiles (selections of cipher suites and algorithms).
+
+
+The .pem files are certificate and keys corresponding to the chains
+and anchors used by the sample client and server. They are provided
+for reference only; these files are not used by the examples.
--- /dev/null
+-----BEGIN CERTIFICATE-----
+MIICcTCCAVmgAwIBAgIUbmO7Sc5BfgOM9Ubyiq5hCDWwlLMwDQYJKoZIhvcNAQELBQAwJzELMAkG
+A1UEBhMCQ0ExGDAWBgNVBAMTD0ludGVybWVkaWF0ZSBDQTAeFw0xMDAxMDEwMDAwMDBaFw0zNzEy
+MzEyMzU5NTlaMCExCzAJBgNVBAYTAkNBMRIwEAYDVQQDEwlsb2NhbGhvc3QwWTATBgcqhkjOPQIB
+BggqhkjOPQMBBwNCAARfOJ2n/02Kr/Y0OUYa/Drf9COqqer7xQjeAI6+eaU3WExt3QHKq0ffibbH
+Fx84/B0gFN1FwOCPk044C/zpmaFJo2YwZDAfBgNVHSMEGDAWgBR8z6PGKffzxaoZ0MAW6+BAD85E
+pzAdBgNVHQ4EFgQUww6GqnW0FcDllQkyvl6SdankRJswDAYDVR0TAQH/BAIwADAUBgNVHREEDTAL
+gglsb2NhbGhvc3QwDQYJKoZIhvcNAQELBQADggEBAI6JY6ebqBCOnhjQpHrdLIIWjwsO1cpXu19v
+/FcowCG6rZSoF0JF1zH3hFcZRiQ8x0k4P0h6CRrrUbrFdY5MsiWwxyI+5+VG27E2/BuFUbDtgxbw
+OnnaXShq7mogTLBwXrDtem0tGsm0ccLEox0lhjBUsZgmwVHg+DGtZ0id5qFSOyBHyXDagLWk9D9y
+azcwVzksRptE8dlOu6Zf45rFf2y2Zcu/QHKS0Gj2rnl+JMFbaDAoU3FhevQ2ezvCtuwf3DBABA3q
+swrPddO9nqtxcWh/pUFSAOmzruQe8btpxjvV3tLCJWkIPDfM94Jq5ah7agLavaQBMzPz3kYA7HXP
+4H0=
+-----END CERTIFICATE-----
--- /dev/null
+-----BEGIN CERTIFICATE-----
+MIIBsDCCAVagAwIBAgIUHE0AkWniRqyQfGRcU/H/t8HLbnowCgYIKoZIzj0EAwIwJzELMAkGA1UE
+BhMCQ0ExGDAWBgNVBAMTD0ludGVybWVkaWF0ZSBDQTAeFw0xMDAxMDEwMDAwMDBaFw0zNzEyMzEy
+MzU5NTlaMCExCzAJBgNVBAYTAkNBMRIwEAYDVQQDEwlsb2NhbGhvc3QwWTATBgcqhkjOPQIBBggq
+hkjOPQMBBwNCAARfOJ2n/02Kr/Y0OUYa/Drf9COqqer7xQjeAI6+eaU3WExt3QHKq0ffibbHFx84
+/B0gFN1FwOCPk044C/zpmaFJo2YwZDAfBgNVHSMEGDAWgBTw0PEi+XpIFwZ7Pb249c1VnFw+cDAd
+BgNVHQ4EFgQUww6GqnW0FcDllQkyvl6SdankRJswDAYDVR0TAQH/BAIwADAUBgNVHREEDTALggls
+b2NhbGhvc3QwCgYIKoZIzj0EAwIDSAAwRQIhAJH79ATQ5S4B1IzwF2IP3MyAyhjEQHwnA8s0Aw2b
+yFlNAiAFVWni2KFAMzQOfkkyZB0/ax/QLbcvUgRWr9M3j4eZog==
+-----END CERTIFICATE-----
--- /dev/null
+-----BEGIN CERTIFICATE-----
+MIIDPDCCAiSgAwIBAgIUWNq6Ns3toNpcEDNzjgxkknmSrwMwDQYJKoZIhvcNAQELBQAwJzELMAkG
+A1UEBhMCQ0ExGDAWBgNVBAMTD0ludGVybWVkaWF0ZSBDQTAeFw0xMDAxMDEwMDAwMDBaFw0zNzEy
+MzEyMzU5NTlaMCExCzAJBgNVBAYTAkNBMRIwEAYDVQQDEwlsb2NhbGhvc3QwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQDUeh0nuis6Z7KRavvng0TK7Rx1rd1Ng2LWqmiVsiQhexWuKplo
+Fe1m8LhY59P1LsbZKl7nDi7n/GdZwMhhfUukb92f2ciFh2THuhoPKdSWqHiaa2IgqTLQ7qmMKGFH
+olAqY/Yh3trY1fB/xQCCcOajv1yJJ09RkncDw7DMLjvsI/IvU0GviZP/0oCxQ5fe1hmgkhJ6PWZ5
+4cG84Xdwoos9RoRTP+ROQkE3kh4f/Tiz9++HOYDTVs/04BPeZLBypAOExEHtb/o+4soEINLX3CyC
+K3ribaEcSNvPiU80lz0oqFPa58HhcxWjMHZ/jyNCFD1RNNJarTyby8j+f26OQPO9AgMBAAGjZjBk
+MB8GA1UdIwQYMBaAFMUBrXzmY8mcF1/FoqfhUF/o9ajGMB0GA1UdDgQWBBTFAa185mPJnBdfxaKn
+4VBf6PWoxjAMBgNVHRMBAf8EAjAAMBQGA1UdEQQNMAuCCWxvY2FsaG9zdDANBgkqhkiG9w0BAQsF
+AAOCAQEAcbNdIcIO19DG+Epzh00iAifQx/j9Gm1iWIIIdiAHwEiS8+mYWusNTlaVY2hNq9QAduA3
+zwsRYVlc3valFFnZJZ9Z2dNehqwdpiwyQhkyE0ALVM1nJra9tJakyh9/N9aodes6gVEwuflKAW/R
+1u1P3z8wYAZnko5hhV8atYyzD2Gp+t9dxGQA6oexM199y6OFJG4sZTvqcz+G0/3o5ALGYWomF1IB
+JVx/qM5pH6xhLLcEr/2kepnLJhVM/3TUcwxXDCbr1yrcXMNBu8Lzzha9jnv76d+rIQ2Rs43Yz8j0
+SbnQ4xZwP7Pe1Acl+kZEUolNicjiyrUzf8chvSjv/mZ0Aw==
+-----END CERTIFICATE-----
--- /dev/null
+-----BEGIN CERTIFICATE-----
+MIIBqTCCAU6gAwIBAgIUINPr4oz+2uajLF478mY6KzZ7sMowCgYIKoZIzj0EAwIwHDELMAkGA1UE
+BhMCQ0ExDTALBgNVBAMTBFJvb3QwHhcNMTAwMTAxMDAwMDAwWhcNMzcxMjMxMjM1OTU5WjAnMQsw
+CQYDVQQGEwJDQTEYMBYGA1UEAxMPSW50ZXJtZWRpYXRlIENBMFkwEwYHKoZIzj0CAQYIKoZIzj0D
+AQcDQgAEcC6SggEXbG2r4dFjCUhJ0qY1UtM8c7uyiDeYh/GN4Oxlmg4T9e2RYci2bTOEbq6OVYDN
+SZ4Hv9CunebQsycWoaNjMGEwHwYDVR0jBBgwFoAUlUG04meq8X+8j3nzaBRaa5IWokAwHQYDVR0O
+BBYEFPDQ8SL5ekgXBns9vbj1zVWcXD5wMA4GA1UdDwEB/wQEAwIAhjAPBgNVHRMBAf8EBTADAQH/
+MAoGCCqGSM49BAMCA0kAMEYCIQCF40ZomdYCellmHLdPNS0INjhhfgVI2GlDH+tW6a0GDgIhAIJw
+tGIDSUbIVFkF2XjbUxzgbmb1DxQ7yS04EnCRVvmp
+-----END CERTIFICATE-----
--- /dev/null
+-----BEGIN CERTIFICATE-----
+MIIDNDCCAhygAwIBAgIUcA9g7vAHmpxprJdiJk9dBbb5j0gwDQYJKoZIhvcNAQELBQAwHDELMAkG
+A1UEBhMCQ0ExDTALBgNVBAMTBFJvb3QwHhcNMTAwMTAxMDAwMDAwWhcNMzcxMjMxMjM1OTU5WjAn
+MQswCQYDVQQGEwJDQTEYMBYGA1UEAxMPSW50ZXJtZWRpYXRlIENBMIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEAs+hrr5wWUuOBDFCrJc7MDcfyH39Q3yxcNdZiLmMnQafkU6hLJ/oTkaP6
+CUovO17Pd7OKwc1JlZx1DWR07+TXS7mhm2jSMHFI6vdLFN8/R6nYu+yPKMz637QflHyW/AgFKPno
+9C8v7mKcijrghVhgtg8tMLTAQVSRTB9frfEZ8MAipn3YP3k0WUJ7W7VBxGR/Us88NyKhL3kllCRB
+wj/6x3X7SLUNGKf0VPMubthDWMSrUOgFrZG2HgF1s1Sc3qCZFfus8VyXSVHM71gSb3NrszQUAQ9a
+nfqq1pPT4urDq7xO7cxRobj4lLa0LKiGKx/2UUMpUl4TibNqeGBOTsAbpQIDAQABo2MwYTAfBgNV
+HSMEGDAWgBTDCry0kGOWkkW8J6DwWIkq1XgAEjAdBgNVHQ4EFgQUfM+jxin388WqGdDAFuvgQA/O
+RKcwDgYDVR0PAQH/BAQDAgCGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFQ7
+9OrG5OjAWxKyrfq9qfRiA61XTG8Hp0c1dT5IoltxEAGPk5mdp0fjjj6vLboG/tTkl7wQjaalOjzm
+Ics72hPjSiPrvLqlkJGtVW7V3YVLayfSOXYGLtQjW7tVtUk/fS8hy5Z1GZmpmfELuz7HEKeLelK5
+SeQUCHjnPdmYV9r/2rmNZnWAtV2532ll2xbnHsRA5EaKHnYyFueDZ9p4VqsPTFzxcNpmIPT4D/bc
+L3KXa3hAeZ1bbb4DznBCqCpxEd8ugQHqhhKRT9AY7YSkSDC5uXtWPu+N4R/9kLJEhVhvpzB0fPGu
+jJk/8U1XxZVowjay7MJoesCBqVUF58+vUKw=
+-----END CERTIFICATE-----
--- /dev/null
+-----BEGIN CERTIFICATE-----
+MIIBijCCATCgAwIBAgIBCTAKBggqhkjOPQQDAjAcMQswCQYDVQQGEwJDQTENMAsGA1UEAxMEUm9v
+dDAeFw0xMDAxMDEwMDAwMDBaFw0zNzEyMzEyMzU5NTlaMBwxCzAJBgNVBAYTAkNBMQ0wCwYDVQQD
+EwRSb290MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEcXS6q7kwLoHV5Vf58yBoDJz5ZNu0IA1t
+6kDQSm5C/baaaCVE9t97xPze3Xu7xdt8dj9BZkBu26eHwuXYxfN/jaNjMGEwHwYDVR0jBBgwFoAU
+lUG04meq8X+8j3nzaBRaa5IWokAwHQYDVR0OBBYEFJVBtOJnqvF/vI9582gUWmuSFqJAMA4GA1Ud
+DwEB/wQEAwIAhjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0gAMEUCIQCz1GCIAoRtqU2h
+x62hec7E+/XxnUGDORWnkliiGrcmxQIgNPq9NHD7ts0xYjTwZsd0bN62+iY93lM4LHbkNV9q/gA=
+-----END CERTIFICATE-----
--- /dev/null
+-----BEGIN CERTIFICATE-----
+MIIDFjCCAf6gAwIBAgIBCDANBgkqhkiG9w0BAQsFADAcMQswCQYDVQQGEwJDQTENMAsGA1UEAxME
+Um9vdDAeFw0xMDAxMDEwMDAwMDBaFw0zNzEyMzEyMzU5NTlaMBwxCzAJBgNVBAYTAkNBMQ0wCwYD
+VQQDEwRSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAttk01FD9s696c/HOOL9d
+b0Xh/U6xmMZggybSF9HFt5qjwd5jOZec8F5cyBwXuYgZbfC2LjBQoVRuk8DbzzDLnx4nefHDmVI1
+qj2237CtfMtJzcDt52YQKunOKB8hUPp3TC3a7zxY606/zun7Gtqjg6PNo8qTgNza8xfMeqszgJyy
+1H9GP8U83GGUtycpbiq8Wwk21MY7Deu+ztsdHLwQanFxs/LKKJp38orsQu+xSo7i8hoyKs3ApkYs
+msKFN5F/RqGTgaF0Zt+6szkgkZP6HaGohefk+Qf2EPaoJwG2fxLDQMPJ4rCrSRg6ZLZZt5W1ljbf
+ImmqcmpUTicpow6XFQIDAQABo2MwYTAfBgNVHSMEGDAWgBTDCry0kGOWkkW8J6DwWIkq1XgAEjAd
+BgNVHQ4EFgQUwwq8tJBjlpJFvCeg8FiJKtV4ABIwDgYDVR0PAQH/BAQDAgCGMA8GA1UdEwEB/wQF
+MAMBAf8wDQYJKoZIhvcNAQELBQADggEBAA7SaR2V1Gx71RiL5Cdfr15jkU88snnm+v+0PvIfQrNP
+4RzKJkaD3j//oZf6Hr2yH6c7Bi3OhCxBFNbXjDXiAXVRoTjOSxNSwVq43utl9Z4IKAZzQlEYW5S5
+U0oskEq2q6jDEWoj8lUtQW4GAVuZhq7lNs0jJJu84IBsxHJFgZJ/7+LHFLXs+vQkz3hjzMZ7gIt+
+lwXI/gdY9ld1QB6WLLIzxs7zid+Z0LZTYi851vbmMwUqgL8V5Np0Q0EVHHy1c6LQ0hj1kVLay2ZN
+d2dsUMCQJI5EF2kWon+xFDpAtv0vUT2xuMkYFhjS/aBxzevWCsXuUQphBYaIGli8P68NNPo=
+-----END CERTIFICATE-----
--- /dev/null
+/*
+ * 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 "bearssl.h"
+
+/*
+ * A sample server certificate chain with a single intermediate CA.
+ * Certificate key type: EC
+ * Signing algorithm for both certificates: RSA
+ */
+
+static const unsigned char CERT0[] = {
+ 0x30, 0x82, 0x02, 0x71, 0x30, 0x82, 0x01, 0x59, 0xA0, 0x03, 0x02, 0x01,
+ 0x02, 0x02, 0x14, 0x6E, 0x63, 0xBB, 0x49, 0xCE, 0x41, 0x7E, 0x03, 0x8C,
+ 0xF5, 0x46, 0xF2, 0x8A, 0xAE, 0x61, 0x08, 0x35, 0xB0, 0x94, 0xB3, 0x30,
+ 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B,
+ 0x05, 0x00, 0x30, 0x27, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
+ 0x06, 0x13, 0x02, 0x43, 0x41, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55,
+ 0x04, 0x03, 0x13, 0x0F, 0x49, 0x6E, 0x74, 0x65, 0x72, 0x6D, 0x65, 0x64,
+ 0x69, 0x61, 0x74, 0x65, 0x20, 0x43, 0x41, 0x30, 0x1E, 0x17, 0x0D, 0x31,
+ 0x30, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5A,
+ 0x17, 0x0D, 0x33, 0x37, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, 0x39,
+ 0x35, 0x39, 0x5A, 0x30, 0x21, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55,
+ 0x04, 0x06, 0x13, 0x02, 0x43, 0x41, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03,
+ 0x55, 0x04, 0x03, 0x13, 0x09, 0x6C, 0x6F, 0x63, 0x61, 0x6C, 0x68, 0x6F,
+ 0x73, 0x74, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE,
+ 0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01,
+ 0x07, 0x03, 0x42, 0x00, 0x04, 0x5F, 0x38, 0x9D, 0xA7, 0xFF, 0x4D, 0x8A,
+ 0xAF, 0xF6, 0x34, 0x39, 0x46, 0x1A, 0xFC, 0x3A, 0xDF, 0xF4, 0x23, 0xAA,
+ 0xA9, 0xEA, 0xFB, 0xC5, 0x08, 0xDE, 0x00, 0x8E, 0xBE, 0x79, 0xA5, 0x37,
+ 0x58, 0x4C, 0x6D, 0xDD, 0x01, 0xCA, 0xAB, 0x47, 0xDF, 0x89, 0xB6, 0xC7,
+ 0x17, 0x1F, 0x38, 0xFC, 0x1D, 0x20, 0x14, 0xDD, 0x45, 0xC0, 0xE0, 0x8F,
+ 0x93, 0x4E, 0x38, 0x0B, 0xFC, 0xE9, 0x99, 0xA1, 0x49, 0xA3, 0x66, 0x30,
+ 0x64, 0x30, 0x1F, 0x06, 0x03, 0x55, 0x1D, 0x23, 0x04, 0x18, 0x30, 0x16,
+ 0x80, 0x14, 0x7C, 0xCF, 0xA3, 0xC6, 0x29, 0xF7, 0xF3, 0xC5, 0xAA, 0x19,
+ 0xD0, 0xC0, 0x16, 0xEB, 0xE0, 0x40, 0x0F, 0xCE, 0x44, 0xA7, 0x30, 0x1D,
+ 0x06, 0x03, 0x55, 0x1D, 0x0E, 0x04, 0x16, 0x04, 0x14, 0xC3, 0x0E, 0x86,
+ 0xAA, 0x75, 0xB4, 0x15, 0xC0, 0xE5, 0x95, 0x09, 0x32, 0xBE, 0x5E, 0x92,
+ 0x75, 0xA9, 0xE4, 0x44, 0x9B, 0x30, 0x0C, 0x06, 0x03, 0x55, 0x1D, 0x13,
+ 0x01, 0x01, 0xFF, 0x04, 0x02, 0x30, 0x00, 0x30, 0x14, 0x06, 0x03, 0x55,
+ 0x1D, 0x11, 0x04, 0x0D, 0x30, 0x0B, 0x82, 0x09, 0x6C, 0x6F, 0x63, 0x61,
+ 0x6C, 0x68, 0x6F, 0x73, 0x74, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48,
+ 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01,
+ 0x00, 0x8E, 0x89, 0x63, 0xA7, 0x9B, 0xA8, 0x10, 0x8E, 0x9E, 0x18, 0xD0,
+ 0xA4, 0x7A, 0xDD, 0x2C, 0x82, 0x16, 0x8F, 0x0B, 0x0E, 0xD5, 0xCA, 0x57,
+ 0xBB, 0x5F, 0x6F, 0xFC, 0x57, 0x28, 0xC0, 0x21, 0xBA, 0xAD, 0x94, 0xA8,
+ 0x17, 0x42, 0x45, 0xD7, 0x31, 0xF7, 0x84, 0x57, 0x19, 0x46, 0x24, 0x3C,
+ 0xC7, 0x49, 0x38, 0x3F, 0x48, 0x7A, 0x09, 0x1A, 0xEB, 0x51, 0xBA, 0xC5,
+ 0x75, 0x8E, 0x4C, 0xB2, 0x25, 0xB0, 0xC7, 0x22, 0x3E, 0xE7, 0xE5, 0x46,
+ 0xDB, 0xB1, 0x36, 0xFC, 0x1B, 0x85, 0x51, 0xB0, 0xED, 0x83, 0x16, 0xF0,
+ 0x3A, 0x79, 0xDA, 0x5D, 0x28, 0x6A, 0xEE, 0x6A, 0x20, 0x4C, 0xB0, 0x70,
+ 0x5E, 0xB0, 0xED, 0x7A, 0x6D, 0x2D, 0x1A, 0xC9, 0xB4, 0x71, 0xC2, 0xC4,
+ 0xA3, 0x1D, 0x25, 0x86, 0x30, 0x54, 0xB1, 0x98, 0x26, 0xC1, 0x51, 0xE0,
+ 0xF8, 0x31, 0xAD, 0x67, 0x48, 0x9D, 0xE6, 0xA1, 0x52, 0x3B, 0x20, 0x47,
+ 0xC9, 0x70, 0xDA, 0x80, 0xB5, 0xA4, 0xF4, 0x3F, 0x72, 0x6B, 0x37, 0x30,
+ 0x57, 0x39, 0x2C, 0x46, 0x9B, 0x44, 0xF1, 0xD9, 0x4E, 0xBB, 0xA6, 0x5F,
+ 0xE3, 0x9A, 0xC5, 0x7F, 0x6C, 0xB6, 0x65, 0xCB, 0xBF, 0x40, 0x72, 0x92,
+ 0xD0, 0x68, 0xF6, 0xAE, 0x79, 0x7E, 0x24, 0xC1, 0x5B, 0x68, 0x30, 0x28,
+ 0x53, 0x71, 0x61, 0x7A, 0xF4, 0x36, 0x7B, 0x3B, 0xC2, 0xB6, 0xEC, 0x1F,
+ 0xDC, 0x30, 0x40, 0x04, 0x0D, 0xEA, 0xB3, 0x0A, 0xCF, 0x75, 0xD3, 0xBD,
+ 0x9E, 0xAB, 0x71, 0x71, 0x68, 0x7F, 0xA5, 0x41, 0x52, 0x00, 0xE9, 0xB3,
+ 0xAE, 0xE4, 0x1E, 0xF1, 0xBB, 0x69, 0xC6, 0x3B, 0xD5, 0xDE, 0xD2, 0xC2,
+ 0x25, 0x69, 0x08, 0x3C, 0x37, 0xCC, 0xF7, 0x82, 0x6A, 0xE5, 0xA8, 0x7B,
+ 0x6A, 0x02, 0xDA, 0xBD, 0xA4, 0x01, 0x33, 0x33, 0xF3, 0xDE, 0x46, 0x00,
+ 0xEC, 0x75, 0xCF, 0xE0, 0x7D
+};
+
+static const unsigned char CERT1[] = {
+ 0x30, 0x82, 0x03, 0x34, 0x30, 0x82, 0x02, 0x1C, 0xA0, 0x03, 0x02, 0x01,
+ 0x02, 0x02, 0x14, 0x70, 0x0F, 0x60, 0xEE, 0xF0, 0x07, 0x9A, 0x9C, 0x69,
+ 0xAC, 0x97, 0x62, 0x26, 0x4F, 0x5D, 0x05, 0xB6, 0xF9, 0x8F, 0x48, 0x30,
+ 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B,
+ 0x05, 0x00, 0x30, 0x1C, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
+ 0x06, 0x13, 0x02, 0x43, 0x41, 0x31, 0x0D, 0x30, 0x0B, 0x06, 0x03, 0x55,
+ 0x04, 0x03, 0x13, 0x04, 0x52, 0x6F, 0x6F, 0x74, 0x30, 0x1E, 0x17, 0x0D,
+ 0x31, 0x30, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
+ 0x5A, 0x17, 0x0D, 0x33, 0x37, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35,
+ 0x39, 0x35, 0x39, 0x5A, 0x30, 0x27, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03,
+ 0x55, 0x04, 0x06, 0x13, 0x02, 0x43, 0x41, 0x31, 0x18, 0x30, 0x16, 0x06,
+ 0x03, 0x55, 0x04, 0x03, 0x13, 0x0F, 0x49, 0x6E, 0x74, 0x65, 0x72, 0x6D,
+ 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x20, 0x43, 0x41, 0x30, 0x82, 0x01,
+ 0x22, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01,
+ 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0F, 0x00, 0x30, 0x82, 0x01,
+ 0x0A, 0x02, 0x82, 0x01, 0x01, 0x00, 0xB3, 0xE8, 0x6B, 0xAF, 0x9C, 0x16,
+ 0x52, 0xE3, 0x81, 0x0C, 0x50, 0xAB, 0x25, 0xCE, 0xCC, 0x0D, 0xC7, 0xF2,
+ 0x1F, 0x7F, 0x50, 0xDF, 0x2C, 0x5C, 0x35, 0xD6, 0x62, 0x2E, 0x63, 0x27,
+ 0x41, 0xA7, 0xE4, 0x53, 0xA8, 0x4B, 0x27, 0xFA, 0x13, 0x91, 0xA3, 0xFA,
+ 0x09, 0x4A, 0x2F, 0x3B, 0x5E, 0xCF, 0x77, 0xB3, 0x8A, 0xC1, 0xCD, 0x49,
+ 0x95, 0x9C, 0x75, 0x0D, 0x64, 0x74, 0xEF, 0xE4, 0xD7, 0x4B, 0xB9, 0xA1,
+ 0x9B, 0x68, 0xD2, 0x30, 0x71, 0x48, 0xEA, 0xF7, 0x4B, 0x14, 0xDF, 0x3F,
+ 0x47, 0xA9, 0xD8, 0xBB, 0xEC, 0x8F, 0x28, 0xCC, 0xFA, 0xDF, 0xB4, 0x1F,
+ 0x94, 0x7C, 0x96, 0xFC, 0x08, 0x05, 0x28, 0xF9, 0xE8, 0xF4, 0x2F, 0x2F,
+ 0xEE, 0x62, 0x9C, 0x8A, 0x3A, 0xE0, 0x85, 0x58, 0x60, 0xB6, 0x0F, 0x2D,
+ 0x30, 0xB4, 0xC0, 0x41, 0x54, 0x91, 0x4C, 0x1F, 0x5F, 0xAD, 0xF1, 0x19,
+ 0xF0, 0xC0, 0x22, 0xA6, 0x7D, 0xD8, 0x3F, 0x79, 0x34, 0x59, 0x42, 0x7B,
+ 0x5B, 0xB5, 0x41, 0xC4, 0x64, 0x7F, 0x52, 0xCF, 0x3C, 0x37, 0x22, 0xA1,
+ 0x2F, 0x79, 0x25, 0x94, 0x24, 0x41, 0xC2, 0x3F, 0xFA, 0xC7, 0x75, 0xFB,
+ 0x48, 0xB5, 0x0D, 0x18, 0xA7, 0xF4, 0x54, 0xF3, 0x2E, 0x6E, 0xD8, 0x43,
+ 0x58, 0xC4, 0xAB, 0x50, 0xE8, 0x05, 0xAD, 0x91, 0xB6, 0x1E, 0x01, 0x75,
+ 0xB3, 0x54, 0x9C, 0xDE, 0xA0, 0x99, 0x15, 0xFB, 0xAC, 0xF1, 0x5C, 0x97,
+ 0x49, 0x51, 0xCC, 0xEF, 0x58, 0x12, 0x6F, 0x73, 0x6B, 0xB3, 0x34, 0x14,
+ 0x01, 0x0F, 0x5A, 0x9D, 0xFA, 0xAA, 0xD6, 0x93, 0xD3, 0xE2, 0xEA, 0xC3,
+ 0xAB, 0xBC, 0x4E, 0xED, 0xCC, 0x51, 0xA1, 0xB8, 0xF8, 0x94, 0xB6, 0xB4,
+ 0x2C, 0xA8, 0x86, 0x2B, 0x1F, 0xF6, 0x51, 0x43, 0x29, 0x52, 0x5E, 0x13,
+ 0x89, 0xB3, 0x6A, 0x78, 0x60, 0x4E, 0x4E, 0xC0, 0x1B, 0xA5, 0x02, 0x03,
+ 0x01, 0x00, 0x01, 0xA3, 0x63, 0x30, 0x61, 0x30, 0x1F, 0x06, 0x03, 0x55,
+ 0x1D, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xC3, 0x0A, 0xBC, 0xB4,
+ 0x90, 0x63, 0x96, 0x92, 0x45, 0xBC, 0x27, 0xA0, 0xF0, 0x58, 0x89, 0x2A,
+ 0xD5, 0x78, 0x00, 0x12, 0x30, 0x1D, 0x06, 0x03, 0x55, 0x1D, 0x0E, 0x04,
+ 0x16, 0x04, 0x14, 0x7C, 0xCF, 0xA3, 0xC6, 0x29, 0xF7, 0xF3, 0xC5, 0xAA,
+ 0x19, 0xD0, 0xC0, 0x16, 0xEB, 0xE0, 0x40, 0x0F, 0xCE, 0x44, 0xA7, 0x30,
+ 0x0E, 0x06, 0x03, 0x55, 0x1D, 0x0F, 0x01, 0x01, 0xFF, 0x04, 0x04, 0x03,
+ 0x02, 0x00, 0x86, 0x30, 0x0F, 0x06, 0x03, 0x55, 0x1D, 0x13, 0x01, 0x01,
+ 0xFF, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xFF, 0x30, 0x0D, 0x06, 0x09,
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x03,
+ 0x82, 0x01, 0x01, 0x00, 0x54, 0x3B, 0xF4, 0xEA, 0xC6, 0xE4, 0xE8, 0xC0,
+ 0x5B, 0x12, 0xB2, 0xAD, 0xFA, 0xBD, 0xA9, 0xF4, 0x62, 0x03, 0xAD, 0x57,
+ 0x4C, 0x6F, 0x07, 0xA7, 0x47, 0x35, 0x75, 0x3E, 0x48, 0xA2, 0x5B, 0x71,
+ 0x10, 0x01, 0x8F, 0x93, 0x99, 0x9D, 0xA7, 0x47, 0xE3, 0x8E, 0x3E, 0xAF,
+ 0x2D, 0xBA, 0x06, 0xFE, 0xD4, 0xE4, 0x97, 0xBC, 0x10, 0x8D, 0xA6, 0xA5,
+ 0x3A, 0x3C, 0xE6, 0x21, 0xCB, 0x3B, 0xDA, 0x13, 0xE3, 0x4A, 0x23, 0xEB,
+ 0xBC, 0xBA, 0xA5, 0x90, 0x91, 0xAD, 0x55, 0x6E, 0xD5, 0xDD, 0x85, 0x4B,
+ 0x6B, 0x27, 0xD2, 0x39, 0x76, 0x06, 0x2E, 0xD4, 0x23, 0x5B, 0xBB, 0x55,
+ 0xB5, 0x49, 0x3F, 0x7D, 0x2F, 0x21, 0xCB, 0x96, 0x75, 0x19, 0x99, 0xA9,
+ 0x99, 0xF1, 0x0B, 0xBB, 0x3E, 0xC7, 0x10, 0xA7, 0x8B, 0x7A, 0x52, 0xB9,
+ 0x49, 0xE4, 0x14, 0x08, 0x78, 0xE7, 0x3D, 0xD9, 0x98, 0x57, 0xDA, 0xFF,
+ 0xDA, 0xB9, 0x8D, 0x66, 0x75, 0x80, 0xB5, 0x5D, 0xB9, 0xDF, 0x69, 0x65,
+ 0xDB, 0x16, 0xE7, 0x1E, 0xC4, 0x40, 0xE4, 0x46, 0x8A, 0x1E, 0x76, 0x32,
+ 0x16, 0xE7, 0x83, 0x67, 0xDA, 0x78, 0x56, 0xAB, 0x0F, 0x4C, 0x5C, 0xF1,
+ 0x70, 0xDA, 0x66, 0x20, 0xF4, 0xF8, 0x0F, 0xF6, 0xDC, 0x2F, 0x72, 0x97,
+ 0x6B, 0x78, 0x40, 0x79, 0x9D, 0x5B, 0x6D, 0xBE, 0x03, 0xCE, 0x70, 0x42,
+ 0xA8, 0x2A, 0x71, 0x11, 0xDF, 0x2E, 0x81, 0x01, 0xEA, 0x86, 0x12, 0x91,
+ 0x4F, 0xD0, 0x18, 0xED, 0x84, 0xA4, 0x48, 0x30, 0xB9, 0xB9, 0x7B, 0x56,
+ 0x3E, 0xEF, 0x8D, 0xE1, 0x1F, 0xFD, 0x90, 0xB2, 0x44, 0x85, 0x58, 0x6F,
+ 0xA7, 0x30, 0x74, 0x7C, 0xF1, 0xAE, 0x8C, 0x99, 0x3F, 0xF1, 0x4D, 0x57,
+ 0xC5, 0x95, 0x68, 0xC2, 0x36, 0xB2, 0xEC, 0xC2, 0x68, 0x7A, 0xC0, 0x81,
+ 0xA9, 0x55, 0x05, 0xE7, 0xCF, 0xAF, 0x50, 0xAC
+};
+
+static const br_x509_certificate CHAIN[] = {
+ { (unsigned char *)CERT0, sizeof CERT0 },
+ { (unsigned char *)CERT1, sizeof CERT1 }
+};
+
+#define CHAIN_LEN 2
--- /dev/null
+/*
+ * 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 "bearssl.h"
+
+/*
+ * A sample server certificate chain with a single intermediate CA.
+ * Certificate key type: EC
+ * Signing algorithm for both certificates: ECDSA
+ */
+
+static const unsigned char CERT0[] = {
+ 0x30, 0x82, 0x01, 0xB0, 0x30, 0x82, 0x01, 0x56, 0xA0, 0x03, 0x02, 0x01,
+ 0x02, 0x02, 0x14, 0x1C, 0x4D, 0x00, 0x91, 0x69, 0xE2, 0x46, 0xAC, 0x90,
+ 0x7C, 0x64, 0x5C, 0x53, 0xF1, 0xFF, 0xB7, 0xC1, 0xCB, 0x6E, 0x7A, 0x30,
+ 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02, 0x30,
+ 0x27, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+ 0x43, 0x41, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
+ 0x0F, 0x49, 0x6E, 0x74, 0x65, 0x72, 0x6D, 0x65, 0x64, 0x69, 0x61, 0x74,
+ 0x65, 0x20, 0x43, 0x41, 0x30, 0x1E, 0x17, 0x0D, 0x31, 0x30, 0x30, 0x31,
+ 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5A, 0x17, 0x0D, 0x33,
+ 0x37, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5A,
+ 0x30, 0x21, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+ 0x02, 0x43, 0x41, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x03,
+ 0x13, 0x09, 0x6C, 0x6F, 0x63, 0x61, 0x6C, 0x68, 0x6F, 0x73, 0x74, 0x30,
+ 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01,
+ 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03, 0x42,
+ 0x00, 0x04, 0x5F, 0x38, 0x9D, 0xA7, 0xFF, 0x4D, 0x8A, 0xAF, 0xF6, 0x34,
+ 0x39, 0x46, 0x1A, 0xFC, 0x3A, 0xDF, 0xF4, 0x23, 0xAA, 0xA9, 0xEA, 0xFB,
+ 0xC5, 0x08, 0xDE, 0x00, 0x8E, 0xBE, 0x79, 0xA5, 0x37, 0x58, 0x4C, 0x6D,
+ 0xDD, 0x01, 0xCA, 0xAB, 0x47, 0xDF, 0x89, 0xB6, 0xC7, 0x17, 0x1F, 0x38,
+ 0xFC, 0x1D, 0x20, 0x14, 0xDD, 0x45, 0xC0, 0xE0, 0x8F, 0x93, 0x4E, 0x38,
+ 0x0B, 0xFC, 0xE9, 0x99, 0xA1, 0x49, 0xA3, 0x66, 0x30, 0x64, 0x30, 0x1F,
+ 0x06, 0x03, 0x55, 0x1D, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xF0,
+ 0xD0, 0xF1, 0x22, 0xF9, 0x7A, 0x48, 0x17, 0x06, 0x7B, 0x3D, 0xBD, 0xB8,
+ 0xF5, 0xCD, 0x55, 0x9C, 0x5C, 0x3E, 0x70, 0x30, 0x1D, 0x06, 0x03, 0x55,
+ 0x1D, 0x0E, 0x04, 0x16, 0x04, 0x14, 0xC3, 0x0E, 0x86, 0xAA, 0x75, 0xB4,
+ 0x15, 0xC0, 0xE5, 0x95, 0x09, 0x32, 0xBE, 0x5E, 0x92, 0x75, 0xA9, 0xE4,
+ 0x44, 0x9B, 0x30, 0x0C, 0x06, 0x03, 0x55, 0x1D, 0x13, 0x01, 0x01, 0xFF,
+ 0x04, 0x02, 0x30, 0x00, 0x30, 0x14, 0x06, 0x03, 0x55, 0x1D, 0x11, 0x04,
+ 0x0D, 0x30, 0x0B, 0x82, 0x09, 0x6C, 0x6F, 0x63, 0x61, 0x6C, 0x68, 0x6F,
+ 0x73, 0x74, 0x30, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04,
+ 0x03, 0x02, 0x03, 0x48, 0x00, 0x30, 0x45, 0x02, 0x21, 0x00, 0x91, 0xFB,
+ 0xF4, 0x04, 0xD0, 0xE5, 0x2E, 0x01, 0xD4, 0x8C, 0xF0, 0x17, 0x62, 0x0F,
+ 0xDC, 0xCC, 0x80, 0xCA, 0x18, 0xC4, 0x40, 0x7C, 0x27, 0x03, 0xCB, 0x34,
+ 0x03, 0x0D, 0x9B, 0xC8, 0x59, 0x4D, 0x02, 0x20, 0x05, 0x55, 0x69, 0xE2,
+ 0xD8, 0xA1, 0x40, 0x33, 0x34, 0x0E, 0x7E, 0x49, 0x32, 0x64, 0x1D, 0x3F,
+ 0x6B, 0x1F, 0xD0, 0x2D, 0xB7, 0x2F, 0x52, 0x04, 0x56, 0xAF, 0xD3, 0x37,
+ 0x8F, 0x87, 0x99, 0xA2
+};
+
+static const unsigned char CERT1[] = {
+ 0x30, 0x82, 0x01, 0xA9, 0x30, 0x82, 0x01, 0x4E, 0xA0, 0x03, 0x02, 0x01,
+ 0x02, 0x02, 0x14, 0x20, 0xD3, 0xEB, 0xE2, 0x8C, 0xFE, 0xDA, 0xE6, 0xA3,
+ 0x2C, 0x5E, 0x3B, 0xF2, 0x66, 0x3A, 0x2B, 0x36, 0x7B, 0xB0, 0xCA, 0x30,
+ 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02, 0x30,
+ 0x1C, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+ 0x43, 0x41, 0x31, 0x0D, 0x30, 0x0B, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
+ 0x04, 0x52, 0x6F, 0x6F, 0x74, 0x30, 0x1E, 0x17, 0x0D, 0x31, 0x30, 0x30,
+ 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5A, 0x17, 0x0D,
+ 0x33, 0x37, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39,
+ 0x5A, 0x30, 0x27, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+ 0x13, 0x02, 0x43, 0x41, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04,
+ 0x03, 0x13, 0x0F, 0x49, 0x6E, 0x74, 0x65, 0x72, 0x6D, 0x65, 0x64, 0x69,
+ 0x61, 0x74, 0x65, 0x20, 0x43, 0x41, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07,
+ 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A, 0x86, 0x48,
+ 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x70, 0x2E, 0x92,
+ 0x82, 0x01, 0x17, 0x6C, 0x6D, 0xAB, 0xE1, 0xD1, 0x63, 0x09, 0x48, 0x49,
+ 0xD2, 0xA6, 0x35, 0x52, 0xD3, 0x3C, 0x73, 0xBB, 0xB2, 0x88, 0x37, 0x98,
+ 0x87, 0xF1, 0x8D, 0xE0, 0xEC, 0x65, 0x9A, 0x0E, 0x13, 0xF5, 0xED, 0x91,
+ 0x61, 0xC8, 0xB6, 0x6D, 0x33, 0x84, 0x6E, 0xAE, 0x8E, 0x55, 0x80, 0xCD,
+ 0x49, 0x9E, 0x07, 0xBF, 0xD0, 0xAE, 0x9D, 0xE6, 0xD0, 0xB3, 0x27, 0x16,
+ 0xA1, 0xA3, 0x63, 0x30, 0x61, 0x30, 0x1F, 0x06, 0x03, 0x55, 0x1D, 0x23,
+ 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x95, 0x41, 0xB4, 0xE2, 0x67, 0xAA,
+ 0xF1, 0x7F, 0xBC, 0x8F, 0x79, 0xF3, 0x68, 0x14, 0x5A, 0x6B, 0x92, 0x16,
+ 0xA2, 0x40, 0x30, 0x1D, 0x06, 0x03, 0x55, 0x1D, 0x0E, 0x04, 0x16, 0x04,
+ 0x14, 0xF0, 0xD0, 0xF1, 0x22, 0xF9, 0x7A, 0x48, 0x17, 0x06, 0x7B, 0x3D,
+ 0xBD, 0xB8, 0xF5, 0xCD, 0x55, 0x9C, 0x5C, 0x3E, 0x70, 0x30, 0x0E, 0x06,
+ 0x03, 0x55, 0x1D, 0x0F, 0x01, 0x01, 0xFF, 0x04, 0x04, 0x03, 0x02, 0x00,
+ 0x86, 0x30, 0x0F, 0x06, 0x03, 0x55, 0x1D, 0x13, 0x01, 0x01, 0xFF, 0x04,
+ 0x05, 0x30, 0x03, 0x01, 0x01, 0xFF, 0x30, 0x0A, 0x06, 0x08, 0x2A, 0x86,
+ 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02, 0x03, 0x49, 0x00, 0x30, 0x46, 0x02,
+ 0x21, 0x00, 0x85, 0xE3, 0x46, 0x68, 0x99, 0xD6, 0x02, 0x7A, 0x59, 0x66,
+ 0x1C, 0xB7, 0x4F, 0x35, 0x2D, 0x08, 0x36, 0x38, 0x61, 0x7E, 0x05, 0x48,
+ 0xD8, 0x69, 0x43, 0x1F, 0xEB, 0x56, 0xE9, 0xAD, 0x06, 0x0E, 0x02, 0x21,
+ 0x00, 0x82, 0x70, 0xB4, 0x62, 0x03, 0x49, 0x46, 0xC8, 0x54, 0x59, 0x05,
+ 0xD9, 0x78, 0xDB, 0x53, 0x1C, 0xE0, 0x6E, 0x66, 0xF5, 0x0F, 0x14, 0x3B,
+ 0xC9, 0x2D, 0x38, 0x12, 0x70, 0x91, 0x56, 0xF9, 0xA9
+};
+
+static const br_x509_certificate CHAIN[] = {
+ { (unsigned char *)CERT0, sizeof CERT0 },
+ { (unsigned char *)CERT1, sizeof CERT1 }
+};
+
+#define CHAIN_LEN 2
--- /dev/null
+/*
+ * 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 "bearssl.h"
+
+/*
+ * A sample server certificate chain with a single intermediate CA.
+ * Certificate key type: RSA
+ * Signing algorithm for both certificates: RSA
+ */
+
+static const unsigned char CERT0[] = {
+ 0x30, 0x82, 0x03, 0x3C, 0x30, 0x82, 0x02, 0x24, 0xA0, 0x03, 0x02, 0x01,
+ 0x02, 0x02, 0x14, 0x58, 0xDA, 0xBA, 0x36, 0xCD, 0xED, 0xA0, 0xDA, 0x5C,
+ 0x10, 0x33, 0x73, 0x8E, 0x0C, 0x64, 0x92, 0x79, 0x92, 0xAF, 0x03, 0x30,
+ 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B,
+ 0x05, 0x00, 0x30, 0x27, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
+ 0x06, 0x13, 0x02, 0x43, 0x41, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55,
+ 0x04, 0x03, 0x13, 0x0F, 0x49, 0x6E, 0x74, 0x65, 0x72, 0x6D, 0x65, 0x64,
+ 0x69, 0x61, 0x74, 0x65, 0x20, 0x43, 0x41, 0x30, 0x1E, 0x17, 0x0D, 0x31,
+ 0x30, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5A,
+ 0x17, 0x0D, 0x33, 0x37, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, 0x39,
+ 0x35, 0x39, 0x5A, 0x30, 0x21, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55,
+ 0x04, 0x06, 0x13, 0x02, 0x43, 0x41, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03,
+ 0x55, 0x04, 0x03, 0x13, 0x09, 0x6C, 0x6F, 0x63, 0x61, 0x6C, 0x68, 0x6F,
+ 0x73, 0x74, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86,
+ 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01,
+ 0x0F, 0x00, 0x30, 0x82, 0x01, 0x0A, 0x02, 0x82, 0x01, 0x01, 0x00, 0xD4,
+ 0x7A, 0x1D, 0x27, 0xBA, 0x2B, 0x3A, 0x67, 0xB2, 0x91, 0x6A, 0xFB, 0xE7,
+ 0x83, 0x44, 0xCA, 0xED, 0x1C, 0x75, 0xAD, 0xDD, 0x4D, 0x83, 0x62, 0xD6,
+ 0xAA, 0x68, 0x95, 0xB2, 0x24, 0x21, 0x7B, 0x15, 0xAE, 0x2A, 0x99, 0x68,
+ 0x15, 0xED, 0x66, 0xF0, 0xB8, 0x58, 0xE7, 0xD3, 0xF5, 0x2E, 0xC6, 0xD9,
+ 0x2A, 0x5E, 0xE7, 0x0E, 0x2E, 0xE7, 0xFC, 0x67, 0x59, 0xC0, 0xC8, 0x61,
+ 0x7D, 0x4B, 0xA4, 0x6F, 0xDD, 0x9F, 0xD9, 0xC8, 0x85, 0x87, 0x64, 0xC7,
+ 0xBA, 0x1A, 0x0F, 0x29, 0xD4, 0x96, 0xA8, 0x78, 0x9A, 0x6B, 0x62, 0x20,
+ 0xA9, 0x32, 0xD0, 0xEE, 0xA9, 0x8C, 0x28, 0x61, 0x47, 0xA2, 0x50, 0x2A,
+ 0x63, 0xF6, 0x21, 0xDE, 0xDA, 0xD8, 0xD5, 0xF0, 0x7F, 0xC5, 0x00, 0x82,
+ 0x70, 0xE6, 0xA3, 0xBF, 0x5C, 0x89, 0x27, 0x4F, 0x51, 0x92, 0x77, 0x03,
+ 0xC3, 0xB0, 0xCC, 0x2E, 0x3B, 0xEC, 0x23, 0xF2, 0x2F, 0x53, 0x41, 0xAF,
+ 0x89, 0x93, 0xFF, 0xD2, 0x80, 0xB1, 0x43, 0x97, 0xDE, 0xD6, 0x19, 0xA0,
+ 0x92, 0x12, 0x7A, 0x3D, 0x66, 0x79, 0xE1, 0xC1, 0xBC, 0xE1, 0x77, 0x70,
+ 0xA2, 0x8B, 0x3D, 0x46, 0x84, 0x53, 0x3F, 0xE4, 0x4E, 0x42, 0x41, 0x37,
+ 0x92, 0x1E, 0x1F, 0xFD, 0x38, 0xB3, 0xF7, 0xEF, 0x87, 0x39, 0x80, 0xD3,
+ 0x56, 0xCF, 0xF4, 0xE0, 0x13, 0xDE, 0x64, 0xB0, 0x72, 0xA4, 0x03, 0x84,
+ 0xC4, 0x41, 0xED, 0x6F, 0xFA, 0x3E, 0xE2, 0xCA, 0x04, 0x20, 0xD2, 0xD7,
+ 0xDC, 0x2C, 0x82, 0x2B, 0x7A, 0xE2, 0x6D, 0xA1, 0x1C, 0x48, 0xDB, 0xCF,
+ 0x89, 0x4F, 0x34, 0x97, 0x3D, 0x28, 0xA8, 0x53, 0xDA, 0xE7, 0xC1, 0xE1,
+ 0x73, 0x15, 0xA3, 0x30, 0x76, 0x7F, 0x8F, 0x23, 0x42, 0x14, 0x3D, 0x51,
+ 0x34, 0xD2, 0x5A, 0xAD, 0x3C, 0x9B, 0xCB, 0xC8, 0xFE, 0x7F, 0x6E, 0x8E,
+ 0x40, 0xF3, 0xBD, 0x02, 0x03, 0x01, 0x00, 0x01, 0xA3, 0x66, 0x30, 0x64,
+ 0x30, 0x1F, 0x06, 0x03, 0x55, 0x1D, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80,
+ 0x14, 0xC5, 0x01, 0xAD, 0x7C, 0xE6, 0x63, 0xC9, 0x9C, 0x17, 0x5F, 0xC5,
+ 0xA2, 0xA7, 0xE1, 0x50, 0x5F, 0xE8, 0xF5, 0xA8, 0xC6, 0x30, 0x1D, 0x06,
+ 0x03, 0x55, 0x1D, 0x0E, 0x04, 0x16, 0x04, 0x14, 0xC5, 0x01, 0xAD, 0x7C,
+ 0xE6, 0x63, 0xC9, 0x9C, 0x17, 0x5F, 0xC5, 0xA2, 0xA7, 0xE1, 0x50, 0x5F,
+ 0xE8, 0xF5, 0xA8, 0xC6, 0x30, 0x0C, 0x06, 0x03, 0x55, 0x1D, 0x13, 0x01,
+ 0x01, 0xFF, 0x04, 0x02, 0x30, 0x00, 0x30, 0x14, 0x06, 0x03, 0x55, 0x1D,
+ 0x11, 0x04, 0x0D, 0x30, 0x0B, 0x82, 0x09, 0x6C, 0x6F, 0x63, 0x61, 0x6C,
+ 0x68, 0x6F, 0x73, 0x74, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86,
+ 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00,
+ 0x71, 0xB3, 0x5D, 0x21, 0xC2, 0x0E, 0xD7, 0xD0, 0xC6, 0xF8, 0x4A, 0x73,
+ 0x87, 0x4D, 0x22, 0x02, 0x27, 0xD0, 0xC7, 0xF8, 0xFD, 0x1A, 0x6D, 0x62,
+ 0x58, 0x82, 0x08, 0x76, 0x20, 0x07, 0xC0, 0x48, 0x92, 0xF3, 0xE9, 0x98,
+ 0x5A, 0xEB, 0x0D, 0x4E, 0x56, 0x95, 0x63, 0x68, 0x4D, 0xAB, 0xD4, 0x00,
+ 0x76, 0xE0, 0x37, 0xCF, 0x0B, 0x11, 0x61, 0x59, 0x5C, 0xDE, 0xF6, 0xA5,
+ 0x14, 0x59, 0xD9, 0x25, 0x9F, 0x59, 0xD9, 0xD3, 0x5E, 0x86, 0xAC, 0x1D,
+ 0xA6, 0x2C, 0x32, 0x42, 0x19, 0x32, 0x13, 0x40, 0x0B, 0x54, 0xCD, 0x67,
+ 0x26, 0xB6, 0xBD, 0xB4, 0x96, 0xA4, 0xCA, 0x1F, 0x7F, 0x37, 0xD6, 0xA8,
+ 0x75, 0xEB, 0x3A, 0x81, 0x51, 0x30, 0xB9, 0xF9, 0x4A, 0x01, 0x6F, 0xD1,
+ 0xD6, 0xED, 0x4F, 0xDF, 0x3F, 0x30, 0x60, 0x06, 0x67, 0x92, 0x8E, 0x61,
+ 0x85, 0x5F, 0x1A, 0xB5, 0x8C, 0xB3, 0x0F, 0x61, 0xA9, 0xFA, 0xDF, 0x5D,
+ 0xC4, 0x64, 0x00, 0xEA, 0x87, 0xB1, 0x33, 0x5F, 0x7D, 0xCB, 0xA3, 0x85,
+ 0x24, 0x6E, 0x2C, 0x65, 0x3B, 0xEA, 0x73, 0x3F, 0x86, 0xD3, 0xFD, 0xE8,
+ 0xE4, 0x02, 0xC6, 0x61, 0x6A, 0x26, 0x17, 0x52, 0x01, 0x25, 0x5C, 0x7F,
+ 0xA8, 0xCE, 0x69, 0x1F, 0xAC, 0x61, 0x2C, 0xB7, 0x04, 0xAF, 0xFD, 0xA4,
+ 0x7A, 0x99, 0xCB, 0x26, 0x15, 0x4C, 0xFF, 0x74, 0xD4, 0x73, 0x0C, 0x57,
+ 0x0C, 0x26, 0xEB, 0xD7, 0x2A, 0xDC, 0x5C, 0xC3, 0x41, 0xBB, 0xC2, 0xF3,
+ 0xCE, 0x16, 0xBD, 0x8E, 0x7B, 0xFB, 0xE9, 0xDF, 0xAB, 0x21, 0x0D, 0x91,
+ 0xB3, 0x8D, 0xD8, 0xCF, 0xC8, 0xF4, 0x49, 0xB9, 0xD0, 0xE3, 0x16, 0x70,
+ 0x3F, 0xB3, 0xDE, 0xD4, 0x07, 0x25, 0xFA, 0x46, 0x44, 0x52, 0x89, 0x4D,
+ 0x89, 0xC8, 0xE2, 0xCA, 0xB5, 0x33, 0x7F, 0xC7, 0x21, 0xBD, 0x28, 0xEF,
+ 0xFE, 0x66, 0x74, 0x03
+};
+
+static const unsigned char CERT1[] = {
+ 0x30, 0x82, 0x03, 0x34, 0x30, 0x82, 0x02, 0x1C, 0xA0, 0x03, 0x02, 0x01,
+ 0x02, 0x02, 0x14, 0x70, 0x0F, 0x60, 0xEE, 0xF0, 0x07, 0x9A, 0x9C, 0x69,
+ 0xAC, 0x97, 0x62, 0x26, 0x4F, 0x5D, 0x05, 0xB6, 0xF9, 0x8F, 0x48, 0x30,
+ 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B,
+ 0x05, 0x00, 0x30, 0x1C, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
+ 0x06, 0x13, 0x02, 0x43, 0x41, 0x31, 0x0D, 0x30, 0x0B, 0x06, 0x03, 0x55,
+ 0x04, 0x03, 0x13, 0x04, 0x52, 0x6F, 0x6F, 0x74, 0x30, 0x1E, 0x17, 0x0D,
+ 0x31, 0x30, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
+ 0x5A, 0x17, 0x0D, 0x33, 0x37, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35,
+ 0x39, 0x35, 0x39, 0x5A, 0x30, 0x27, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03,
+ 0x55, 0x04, 0x06, 0x13, 0x02, 0x43, 0x41, 0x31, 0x18, 0x30, 0x16, 0x06,
+ 0x03, 0x55, 0x04, 0x03, 0x13, 0x0F, 0x49, 0x6E, 0x74, 0x65, 0x72, 0x6D,
+ 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x20, 0x43, 0x41, 0x30, 0x82, 0x01,
+ 0x22, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01,
+ 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0F, 0x00, 0x30, 0x82, 0x01,
+ 0x0A, 0x02, 0x82, 0x01, 0x01, 0x00, 0xB3, 0xE8, 0x6B, 0xAF, 0x9C, 0x16,
+ 0x52, 0xE3, 0x81, 0x0C, 0x50, 0xAB, 0x25, 0xCE, 0xCC, 0x0D, 0xC7, 0xF2,
+ 0x1F, 0x7F, 0x50, 0xDF, 0x2C, 0x5C, 0x35, 0xD6, 0x62, 0x2E, 0x63, 0x27,
+ 0x41, 0xA7, 0xE4, 0x53, 0xA8, 0x4B, 0x27, 0xFA, 0x13, 0x91, 0xA3, 0xFA,
+ 0x09, 0x4A, 0x2F, 0x3B, 0x5E, 0xCF, 0x77, 0xB3, 0x8A, 0xC1, 0xCD, 0x49,
+ 0x95, 0x9C, 0x75, 0x0D, 0x64, 0x74, 0xEF, 0xE4, 0xD7, 0x4B, 0xB9, 0xA1,
+ 0x9B, 0x68, 0xD2, 0x30, 0x71, 0x48, 0xEA, 0xF7, 0x4B, 0x14, 0xDF, 0x3F,
+ 0x47, 0xA9, 0xD8, 0xBB, 0xEC, 0x8F, 0x28, 0xCC, 0xFA, 0xDF, 0xB4, 0x1F,
+ 0x94, 0x7C, 0x96, 0xFC, 0x08, 0x05, 0x28, 0xF9, 0xE8, 0xF4, 0x2F, 0x2F,
+ 0xEE, 0x62, 0x9C, 0x8A, 0x3A, 0xE0, 0x85, 0x58, 0x60, 0xB6, 0x0F, 0x2D,
+ 0x30, 0xB4, 0xC0, 0x41, 0x54, 0x91, 0x4C, 0x1F, 0x5F, 0xAD, 0xF1, 0x19,
+ 0xF0, 0xC0, 0x22, 0xA6, 0x7D, 0xD8, 0x3F, 0x79, 0x34, 0x59, 0x42, 0x7B,
+ 0x5B, 0xB5, 0x41, 0xC4, 0x64, 0x7F, 0x52, 0xCF, 0x3C, 0x37, 0x22, 0xA1,
+ 0x2F, 0x79, 0x25, 0x94, 0x24, 0x41, 0xC2, 0x3F, 0xFA, 0xC7, 0x75, 0xFB,
+ 0x48, 0xB5, 0x0D, 0x18, 0xA7, 0xF4, 0x54, 0xF3, 0x2E, 0x6E, 0xD8, 0x43,
+ 0x58, 0xC4, 0xAB, 0x50, 0xE8, 0x05, 0xAD, 0x91, 0xB6, 0x1E, 0x01, 0x75,
+ 0xB3, 0x54, 0x9C, 0xDE, 0xA0, 0x99, 0x15, 0xFB, 0xAC, 0xF1, 0x5C, 0x97,
+ 0x49, 0x51, 0xCC, 0xEF, 0x58, 0x12, 0x6F, 0x73, 0x6B, 0xB3, 0x34, 0x14,
+ 0x01, 0x0F, 0x5A, 0x9D, 0xFA, 0xAA, 0xD6, 0x93, 0xD3, 0xE2, 0xEA, 0xC3,
+ 0xAB, 0xBC, 0x4E, 0xED, 0xCC, 0x51, 0xA1, 0xB8, 0xF8, 0x94, 0xB6, 0xB4,
+ 0x2C, 0xA8, 0x86, 0x2B, 0x1F, 0xF6, 0x51, 0x43, 0x29, 0x52, 0x5E, 0x13,
+ 0x89, 0xB3, 0x6A, 0x78, 0x60, 0x4E, 0x4E, 0xC0, 0x1B, 0xA5, 0x02, 0x03,
+ 0x01, 0x00, 0x01, 0xA3, 0x63, 0x30, 0x61, 0x30, 0x1F, 0x06, 0x03, 0x55,
+ 0x1D, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xC3, 0x0A, 0xBC, 0xB4,
+ 0x90, 0x63, 0x96, 0x92, 0x45, 0xBC, 0x27, 0xA0, 0xF0, 0x58, 0x89, 0x2A,
+ 0xD5, 0x78, 0x00, 0x12, 0x30, 0x1D, 0x06, 0x03, 0x55, 0x1D, 0x0E, 0x04,
+ 0x16, 0x04, 0x14, 0x7C, 0xCF, 0xA3, 0xC6, 0x29, 0xF7, 0xF3, 0xC5, 0xAA,
+ 0x19, 0xD0, 0xC0, 0x16, 0xEB, 0xE0, 0x40, 0x0F, 0xCE, 0x44, 0xA7, 0x30,
+ 0x0E, 0x06, 0x03, 0x55, 0x1D, 0x0F, 0x01, 0x01, 0xFF, 0x04, 0x04, 0x03,
+ 0x02, 0x00, 0x86, 0x30, 0x0F, 0x06, 0x03, 0x55, 0x1D, 0x13, 0x01, 0x01,
+ 0xFF, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xFF, 0x30, 0x0D, 0x06, 0x09,
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x03,
+ 0x82, 0x01, 0x01, 0x00, 0x54, 0x3B, 0xF4, 0xEA, 0xC6, 0xE4, 0xE8, 0xC0,
+ 0x5B, 0x12, 0xB2, 0xAD, 0xFA, 0xBD, 0xA9, 0xF4, 0x62, 0x03, 0xAD, 0x57,
+ 0x4C, 0x6F, 0x07, 0xA7, 0x47, 0x35, 0x75, 0x3E, 0x48, 0xA2, 0x5B, 0x71,
+ 0x10, 0x01, 0x8F, 0x93, 0x99, 0x9D, 0xA7, 0x47, 0xE3, 0x8E, 0x3E, 0xAF,
+ 0x2D, 0xBA, 0x06, 0xFE, 0xD4, 0xE4, 0x97, 0xBC, 0x10, 0x8D, 0xA6, 0xA5,
+ 0x3A, 0x3C, 0xE6, 0x21, 0xCB, 0x3B, 0xDA, 0x13, 0xE3, 0x4A, 0x23, 0xEB,
+ 0xBC, 0xBA, 0xA5, 0x90, 0x91, 0xAD, 0x55, 0x6E, 0xD5, 0xDD, 0x85, 0x4B,
+ 0x6B, 0x27, 0xD2, 0x39, 0x76, 0x06, 0x2E, 0xD4, 0x23, 0x5B, 0xBB, 0x55,
+ 0xB5, 0x49, 0x3F, 0x7D, 0x2F, 0x21, 0xCB, 0x96, 0x75, 0x19, 0x99, 0xA9,
+ 0x99, 0xF1, 0x0B, 0xBB, 0x3E, 0xC7, 0x10, 0xA7, 0x8B, 0x7A, 0x52, 0xB9,
+ 0x49, 0xE4, 0x14, 0x08, 0x78, 0xE7, 0x3D, 0xD9, 0x98, 0x57, 0xDA, 0xFF,
+ 0xDA, 0xB9, 0x8D, 0x66, 0x75, 0x80, 0xB5, 0x5D, 0xB9, 0xDF, 0x69, 0x65,
+ 0xDB, 0x16, 0xE7, 0x1E, 0xC4, 0x40, 0xE4, 0x46, 0x8A, 0x1E, 0x76, 0x32,
+ 0x16, 0xE7, 0x83, 0x67, 0xDA, 0x78, 0x56, 0xAB, 0x0F, 0x4C, 0x5C, 0xF1,
+ 0x70, 0xDA, 0x66, 0x20, 0xF4, 0xF8, 0x0F, 0xF6, 0xDC, 0x2F, 0x72, 0x97,
+ 0x6B, 0x78, 0x40, 0x79, 0x9D, 0x5B, 0x6D, 0xBE, 0x03, 0xCE, 0x70, 0x42,
+ 0xA8, 0x2A, 0x71, 0x11, 0xDF, 0x2E, 0x81, 0x01, 0xEA, 0x86, 0x12, 0x91,
+ 0x4F, 0xD0, 0x18, 0xED, 0x84, 0xA4, 0x48, 0x30, 0xB9, 0xB9, 0x7B, 0x56,
+ 0x3E, 0xEF, 0x8D, 0xE1, 0x1F, 0xFD, 0x90, 0xB2, 0x44, 0x85, 0x58, 0x6F,
+ 0xA7, 0x30, 0x74, 0x7C, 0xF1, 0xAE, 0x8C, 0x99, 0x3F, 0xF1, 0x4D, 0x57,
+ 0xC5, 0x95, 0x68, 0xC2, 0x36, 0xB2, 0xEC, 0xC2, 0x68, 0x7A, 0xC0, 0x81,
+ 0xA9, 0x55, 0x05, 0xE7, 0xCF, 0xAF, 0x50, 0xAC
+};
+
+static const br_x509_certificate CHAIN[] = {
+ { (unsigned char *)CERT0, sizeof CERT0 },
+ { (unsigned char *)CERT1, sizeof CERT1 }
+};
+
+#define CHAIN_LEN 2
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+
+#include "bearssl.h"
+
+/*
+ * Connect to the specified host and port. The connected socket is
+ * returned, or -1 on error.
+ */
+static int
+host_connect(const char *host, const char *port)
+{
+ struct addrinfo hints, *si, *p;
+ int fd;
+ int err;
+
+ memset(&hints, 0, sizeof hints);
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ err = getaddrinfo(host, port, &hints, &si);
+ if (err != 0) {
+ fprintf(stderr, "ERROR: getaddrinfo(): %s\n",
+ gai_strerror(err));
+ return -1;
+ }
+ fd = -1;
+ for (p = si; p != NULL; p = p->ai_next) {
+ struct sockaddr *sa;
+ void *addr;
+ char tmp[INET6_ADDRSTRLEN + 50];
+
+ sa = (struct sockaddr *)p->ai_addr;
+ if (sa->sa_family == AF_INET) {
+ addr = &((struct sockaddr_in *)sa)->sin_addr;
+ } else if (sa->sa_family == AF_INET6) {
+ addr = &((struct sockaddr_in6 *)sa)->sin6_addr;
+ } else {
+ addr = NULL;
+ }
+ if (addr != NULL) {
+ inet_ntop(p->ai_family, addr, tmp, sizeof tmp);
+ } else {
+ sprintf(tmp, "<unknown family: %d>",
+ (int)sa->sa_family);
+ }
+ fprintf(stderr, "connecting to: %s\n", tmp);
+ fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
+ if (fd < 0) {
+ perror("socket()");
+ continue;
+ }
+ if (connect(fd, p->ai_addr, p->ai_addrlen) < 0) {
+ perror("connect()");
+ close(fd);
+ continue;
+ }
+ break;
+ }
+ if (p == NULL) {
+ freeaddrinfo(si);
+ fprintf(stderr, "ERROR: failed to connect\n");
+ return -1;
+ }
+ freeaddrinfo(si);
+ fprintf(stderr, "connected.\n");
+ return fd;
+}
+
+/*
+ * Low-level data read callback for the simplified SSL I/O API.
+ */
+static int
+sock_read(void *ctx, unsigned char *buf, size_t len)
+{
+ for (;;) {
+ ssize_t rlen;
+
+ rlen = read(*(int *)ctx, buf, len);
+ if (rlen <= 0) {
+ if (rlen < 0 && errno == EINTR) {
+ continue;
+ }
+ return -1;
+ }
+ return (int)rlen;
+ }
+}
+
+/*
+ * Low-level data write callback for the simplified SSL I/O API.
+ */
+static int
+sock_write(void *ctx, const unsigned char *buf, size_t len)
+{
+ for (;;) {
+ ssize_t wlen;
+
+ wlen = write(*(int *)ctx, buf, len);
+ if (wlen <= 0) {
+ if (wlen < 0 && errno == EINTR) {
+ continue;
+ }
+ return -1;
+ }
+ return (int)wlen;
+ }
+}
+
+/*
+ * The hardcoded trust anchors. These are the two DN + public key that
+ * correspond to the self-signed certificates cert-root-rsa.pem and
+ * cert-root-ec.pem.
+ *
+ * C code for hardcoded trust anchors can be generated with the "brssl"
+ * command-line tool (with the "ta" command).
+ */
+
+static const unsigned char TA0_DN[] = {
+ 0x30, 0x1C, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+ 0x02, 0x43, 0x41, 0x31, 0x0D, 0x30, 0x0B, 0x06, 0x03, 0x55, 0x04, 0x03,
+ 0x13, 0x04, 0x52, 0x6F, 0x6F, 0x74
+};
+
+static const unsigned char TA0_RSA_N[] = {
+ 0xB6, 0xD9, 0x34, 0xD4, 0x50, 0xFD, 0xB3, 0xAF, 0x7A, 0x73, 0xF1, 0xCE,
+ 0x38, 0xBF, 0x5D, 0x6F, 0x45, 0xE1, 0xFD, 0x4E, 0xB1, 0x98, 0xC6, 0x60,
+ 0x83, 0x26, 0xD2, 0x17, 0xD1, 0xC5, 0xB7, 0x9A, 0xA3, 0xC1, 0xDE, 0x63,
+ 0x39, 0x97, 0x9C, 0xF0, 0x5E, 0x5C, 0xC8, 0x1C, 0x17, 0xB9, 0x88, 0x19,
+ 0x6D, 0xF0, 0xB6, 0x2E, 0x30, 0x50, 0xA1, 0x54, 0x6E, 0x93, 0xC0, 0xDB,
+ 0xCF, 0x30, 0xCB, 0x9F, 0x1E, 0x27, 0x79, 0xF1, 0xC3, 0x99, 0x52, 0x35,
+ 0xAA, 0x3D, 0xB6, 0xDF, 0xB0, 0xAD, 0x7C, 0xCB, 0x49, 0xCD, 0xC0, 0xED,
+ 0xE7, 0x66, 0x10, 0x2A, 0xE9, 0xCE, 0x28, 0x1F, 0x21, 0x50, 0xFA, 0x77,
+ 0x4C, 0x2D, 0xDA, 0xEF, 0x3C, 0x58, 0xEB, 0x4E, 0xBF, 0xCE, 0xE9, 0xFB,
+ 0x1A, 0xDA, 0xA3, 0x83, 0xA3, 0xCD, 0xA3, 0xCA, 0x93, 0x80, 0xDC, 0xDA,
+ 0xF3, 0x17, 0xCC, 0x7A, 0xAB, 0x33, 0x80, 0x9C, 0xB2, 0xD4, 0x7F, 0x46,
+ 0x3F, 0xC5, 0x3C, 0xDC, 0x61, 0x94, 0xB7, 0x27, 0x29, 0x6E, 0x2A, 0xBC,
+ 0x5B, 0x09, 0x36, 0xD4, 0xC6, 0x3B, 0x0D, 0xEB, 0xBE, 0xCE, 0xDB, 0x1D,
+ 0x1C, 0xBC, 0x10, 0x6A, 0x71, 0x71, 0xB3, 0xF2, 0xCA, 0x28, 0x9A, 0x77,
+ 0xF2, 0x8A, 0xEC, 0x42, 0xEF, 0xB1, 0x4A, 0x8E, 0xE2, 0xF2, 0x1A, 0x32,
+ 0x2A, 0xCD, 0xC0, 0xA6, 0x46, 0x2C, 0x9A, 0xC2, 0x85, 0x37, 0x91, 0x7F,
+ 0x46, 0xA1, 0x93, 0x81, 0xA1, 0x74, 0x66, 0xDF, 0xBA, 0xB3, 0x39, 0x20,
+ 0x91, 0x93, 0xFA, 0x1D, 0xA1, 0xA8, 0x85, 0xE7, 0xE4, 0xF9, 0x07, 0xF6,
+ 0x10, 0xF6, 0xA8, 0x27, 0x01, 0xB6, 0x7F, 0x12, 0xC3, 0x40, 0xC3, 0xC9,
+ 0xE2, 0xB0, 0xAB, 0x49, 0x18, 0x3A, 0x64, 0xB6, 0x59, 0xB7, 0x95, 0xB5,
+ 0x96, 0x36, 0xDF, 0x22, 0x69, 0xAA, 0x72, 0x6A, 0x54, 0x4E, 0x27, 0x29,
+ 0xA3, 0x0E, 0x97, 0x15
+};
+
+static const unsigned char TA0_RSA_E[] = {
+ 0x01, 0x00, 0x01
+};
+
+static const unsigned char TA1_DN[] = {
+ 0x30, 0x1C, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+ 0x02, 0x43, 0x41, 0x31, 0x0D, 0x30, 0x0B, 0x06, 0x03, 0x55, 0x04, 0x03,
+ 0x13, 0x04, 0x52, 0x6F, 0x6F, 0x74
+};
+
+static const unsigned char TA1_EC_Q[] = {
+ 0x04, 0x71, 0x74, 0xBA, 0xAB, 0xB9, 0x30, 0x2E, 0x81, 0xD5, 0xE5, 0x57,
+ 0xF9, 0xF3, 0x20, 0x68, 0x0C, 0x9C, 0xF9, 0x64, 0xDB, 0xB4, 0x20, 0x0D,
+ 0x6D, 0xEA, 0x40, 0xD0, 0x4A, 0x6E, 0x42, 0xFD, 0xB6, 0x9A, 0x68, 0x25,
+ 0x44, 0xF6, 0xDF, 0x7B, 0xC4, 0xFC, 0xDE, 0xDD, 0x7B, 0xBB, 0xC5, 0xDB,
+ 0x7C, 0x76, 0x3F, 0x41, 0x66, 0x40, 0x6E, 0xDB, 0xA7, 0x87, 0xC2, 0xE5,
+ 0xD8, 0xC5, 0xF3, 0x7F, 0x8D
+};
+
+static const br_x509_trust_anchor TAs[2] = {
+ {
+ (unsigned char *)TA0_DN, sizeof TA0_DN,
+ BR_X509_TA_CA,
+ {
+ BR_KEYTYPE_RSA,
+ { .rsa = {
+ (unsigned char *)TA0_RSA_N, sizeof TA0_RSA_N,
+ (unsigned char *)TA0_RSA_E, sizeof TA0_RSA_E,
+ } }
+ }
+ },
+ {
+ (unsigned char *)TA1_DN, sizeof TA1_DN,
+ BR_X509_TA_CA,
+ {
+ BR_KEYTYPE_EC,
+ { .ec = {
+ BR_EC_secp256r1,
+ (unsigned char *)TA1_EC_Q, sizeof TA1_EC_Q,
+ } }
+ }
+ }
+};
+
+#define TAs_NUM 2
+
+/*
+ * Main program: this is a simple program that expects 2 or 3 arguments.
+ * The first two arguments are a hostname and a port; the program will
+ * open a SSL connection with that server and port. It will then send
+ * a simple HTTP GET request, using the third argument as target path
+ * ("/" is used as path if no third argument was provided). The HTTP
+ * response, complete with header and contents, is received and written
+ * on stdout.
+ */
+int
+main(int argc, char *argv[])
+{
+ const char *host, *port, *path;
+ int fd;
+ br_ssl_client_context sc;
+ br_x509_minimal_context xc;
+ unsigned char iobuf[BR_SSL_BUFSIZE_BIDI];
+ br_sslio_context ioc;
+
+ /*
+ * Parse command-line argument: host, port, and path. The path
+ * is optional; if absent, "/" is used.
+ */
+ if (argc < 3 || argc > 4) {
+ return EXIT_FAILURE;
+ }
+ host = argv[1];
+ port = argv[2];
+ if (argc == 4) {
+ path = argv[3];
+ } else {
+ path = "/";
+ }
+
+ /*
+ * Open the socket to the target server.
+ */
+ fd = host_connect(host, port);
+ if (fd < 0) {
+ return EXIT_FAILURE;
+ }
+
+ /*
+ * Initialise the client context:
+ * -- Use the "full" profile (all supported algorithms).
+ * -- The provided X.509 validation engine is initialised, with
+ * the hardcoded trust anchor.
+ */
+ br_ssl_client_init_full(&sc, &xc, TAs, TAs_NUM);
+
+ /*
+ * Set the I/O buffer to the provided array. We allocated a
+ * buffer large enough for full-duplex behaviour with all
+ * allowed sizes of SSL records, hence we set the last argument
+ * to 1 (which means "split the buffer into separate input and
+ * output areas").
+ */
+ br_ssl_engine_set_buffer(&sc.eng, iobuf, sizeof iobuf, 1);
+
+ /*
+ * Reset the client context, for a new handshake. We provide the
+ * target host name: it will be used for the SNI extension. The
+ * last parameter is 0: we are not trying to resume a session.
+ */
+ br_ssl_client_reset(&sc, host, 0);
+
+ /*
+ * Initialise the simplified I/O wrapper context, to use our
+ * SSL client context, and the two callbacks for socket I/O.
+ */
+ br_sslio_init(&ioc, &sc.eng, sock_read, &fd, sock_write, &fd);
+
+ /*
+ * Note that while the context has, at that point, already
+ * assembled the ClientHello to send, nothing happened on the
+ * network yet. Real I/O will occur only with the next call.
+ *
+ * We write our simple HTTP request. We could test each call
+ * for an error (-1), but this is not strictly necessary, since
+ * the error state "sticks": if the context fails for any reason
+ * (e.g. bad server certificate), then it will remain in failed
+ * state and all subsequent calls will return -1 as well.
+ */
+ br_sslio_write_all(&ioc, "GET ", 4);
+ br_sslio_write_all(&ioc, path, strlen(path));
+ br_sslio_write_all(&ioc, " HTTP/1.0\r\nHost: ", 17);
+ br_sslio_write_all(&ioc, host, strlen(host));
+ br_sslio_write_all(&ioc, "\r\n\r\n", 4);
+
+ /*
+ * SSL is a buffered protocol: we make sure that all our request
+ * bytes are sent onto the wire.
+ */
+ br_sslio_flush(&ioc);
+
+ /*
+ * Read the server's response. We use here a small 512-byte buffer,
+ * but most of the buffering occurs in the client context: the
+ * server will send full records (up to 16384 bytes worth of data
+ * each), and the client context buffers one full record at a time.
+ */
+ for (;;) {
+ int rlen;
+ unsigned char tmp[512];
+
+ rlen = br_sslio_read(&ioc, tmp, sizeof tmp);
+ if (rlen < 0) {
+ break;
+ }
+ fwrite(tmp, 1, rlen, stdout);
+ }
+
+ /*
+ * Close the socket.
+ */
+ close(fd);
+
+ /*
+ * Check whether we closed properly or not. If the engine is
+ * closed, then its error status allows to distinguish between
+ * a normal closure and a SSL error.
+ *
+ * If the engine is NOT closed, then this means that the
+ * underlying network socket was closed or failed in some way.
+ * Note that many Web servers out there do not properly close
+ * their SSL connections (they don't send a close_notify alert),
+ * which will be reported here as "socket closed without proper
+ * SSL termination".
+ */
+ if (br_ssl_engine_current_state(&sc.eng) == BR_SSL_CLOSED) {
+ int err;
+
+ err = br_ssl_engine_last_error(&sc.eng);
+ if (err == 0) {
+ fprintf(stderr, "closed.\n");
+ return EXIT_SUCCESS;
+ } else {
+ fprintf(stderr, "SSL error %d\n", err);
+ return EXIT_FAILURE;
+ }
+ } else {
+ fprintf(stderr,
+ "socket closed without proper SSL termination\n");
+ return EXIT_FAILURE;
+ }
+}
--- /dev/null
+/*
+ * 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 "bearssl.h"
+
+/*
+ * A "profile" is an initialisation function for a SSL context, that
+ * configures a list of cipher suites and algorithm implementations.
+ * While BearSSL comes with a few predefined profiles, you might one
+ * to define you own, using the example below as guidance.
+ *
+ * Each individual initialisation call sets a parameter or an algorithm
+ * support. Setting a specific algorithm pulls in the implementation of
+ * that algorithm in the compiled binary, as per static linking
+ * behaviour. Removing some of this calls will then reduce total code
+ * footprint, but also mechanically prevents some features to be
+ * supported (protocol versions and cipher suites).
+ *
+ * The two below define profiles for the client and the server contexts,
+ * respectively. Of course, in a typical size-constrained application,
+ * you would use one or the other, not both, to avoid pulling in code
+ * for both.
+ */
+
+void
+example_client_profile(br_ssl_client_context *cc
+ /* and possibly some other arguments */)
+{
+ /*
+ * A list of cipher suites, by preference (first is most
+ * preferred). The list below contains all cipher suites supported
+ * by BearSSL; trim it done to your needs.
+ */
+ static const uint16_t suites[] = {
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ BR_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+ BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
+ BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ BR_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,
+ BR_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,
+ BR_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384,
+ BR_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384,
+ BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
+ BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
+ BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,
+ BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,
+ BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
+ BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
+ BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
+ BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
+ BR_TLS_RSA_WITH_AES_128_GCM_SHA256,
+ BR_TLS_RSA_WITH_AES_256_GCM_SHA384,
+ BR_TLS_RSA_WITH_AES_128_CBC_SHA256,
+ BR_TLS_RSA_WITH_AES_256_CBC_SHA256,
+ BR_TLS_RSA_WITH_AES_128_CBC_SHA,
+ BR_TLS_RSA_WITH_AES_256_CBC_SHA,
+ BR_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ BR_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ BR_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ BR_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
+ BR_TLS_RSA_WITH_3DES_EDE_CBC_SHA
+ };
+
+ /*
+ * Client context must be cleared at some point. This sets
+ * every value and pointer to 0 or NULL.
+ */
+ br_ssl_client_zero(cc);
+
+ /*
+ * Define minimum and maximum protocol versions. Supported
+ * versions are:
+ * BR_TLS10 TLS 1.0
+ * BR_TLS11 TLS 1.1
+ * BR_TLS12 TLS 1.2
+ */
+ br_ssl_engine_set_versions(&cc->eng, BR_TLS10, BR_TLS12);
+
+ /*
+ * Set the PRF implementation(s).
+ * For TLS 1.0 and 1.1, the "prf10" is needed.
+ * For TLS 1.2, this depends on the cipher suite:
+ * -- cipher suites with a name ending in "SHA384" need "prf_sha384";
+ * -- all others need "prf_sha256".
+ *
+ * Note that a cipher suite like TLS_RSA_WITH_AES_128_CBC_SHA will
+ * use SHA-1 for the per-record MAC (that's what the final "SHA"
+ * means), but still SHA-256 for the PRF when selected along with
+ * the TLS-1.2 protocol version.
+ */
+ br_ssl_engine_set_prf10(&cc->eng, &br_tls10_prf);
+ br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf);
+ br_ssl_engine_set_prf_sha384(&cc->eng, &br_tls12_sha384_prf);
+
+ /*
+ * Set hash functions for the engine. Required hash functions
+ * depend on the protocol and cipher suite:
+ *
+ * -- TLS 1.0 and 1.1 require both MD5 and SHA-1.
+ * -- With TLS 1.2, cipher suites with a name ending in "SHA384"
+ * require SHA-384.
+ * -- With TLS 1.2, cipher suites with a name ending in "SHA256"
+ * require SHA-256.
+ * -- With TLS 1.2, cipher suites with a name ending in "SHA"
+ * require both SHA-256 and SHA-1.
+ *
+ * Note that with current implementations, SHA-224 and SHA-256
+ * share the same file, so if you use one, you may have the other
+ * one with no additional overhead. Similarly, SHA-384 and SHA-512
+ * share the same implementation code.
+ */
+ br_ssl_engine_set_hash(&cc->eng, br_md5_ID, &br_md5_vtable);
+ br_ssl_engine_set_hash(&cc->eng, br_sha1_ID, &br_sha1_vtable);
+ br_ssl_engine_set_hash(&cc->eng, br_sha224_ID, &br_sha224_vtable);
+ br_ssl_engine_set_hash(&cc->eng, br_sha256_ID, &br_sha256_vtable);
+ br_ssl_engine_set_hash(&cc->eng, br_sha384_ID, &br_sha384_vtable);
+ br_ssl_engine_set_hash(&cc->eng, br_sha512_ID, &br_sha512_vtable);
+
+ /*
+ * Set the cipher suites. All specified cipher suite MUST be
+ * supported, and the relevant algorithms MUST have been
+ * configured (failure to provide needed implementations may
+ * trigger unwanted behaviours like segfaults or overflows).
+ */
+ br_ssl_engine_set_suites(&cc->eng, suites,
+ (sizeof suites) / (sizeof suites[0]));
+
+ /*
+ * Public-key algorithm imeplementations.
+ *
+ * -- RSA public core ("rsapub") is needed for "RSA" key exchange
+ * (cipher suites whose name starts with TLS_RSA).
+ *
+ * -- RSA signature verification ("rsavrfy") is needed for
+ * "ECDHE_RSA" cipher suites (not ECDH_RSA).
+ *
+ * -- Elliptic curve implementation ("ec") is needed for cipher
+ * suites that use elliptic curves (both "ECDH" and "ECDHE"
+ * cipher suites).
+ *
+ * -- ECDSA signature verification is needed for "ECDHE_ECDSA"
+ * cipher suites (but not for ECDH_ECDSA or ECDH_RSA).
+ *
+ * The RSA code comes in two variants, called "i31" and "i32".
+ * Right now, the "i31" is somewhat faster.
+ */
+ br_ssl_client_set_rsapub(cc, &br_rsa_i31_public);
+ br_ssl_client_set_rsavrfy(cc, &br_rsa_i31_pkcs1_vrfy);
+ br_ssl_engine_set_ec(&cc->eng, &br_ec_prime_i31);
+ br_ssl_client_set_ecdsa(cc, &br_ecdsa_i31_vrfy_asn1);
+
+ /*
+ * Record handler:
+ * -- Cipher suites in AES_128_CBC, AES_256_CBC and 3DES_EDE_CBC
+ * need the CBC record handler ("set_cbc").
+ * -- Cipher suites in AES_128_GCM and AES_256_GCM need the GCM
+ * record handler ("set_gcm").
+ */
+ br_ssl_engine_set_cbc(&cc->eng,
+ &br_sslrec_in_cbc_vtable,
+ &br_sslrec_out_cbc_vtable);
+ br_ssl_engine_set_gcm(&cc->eng,
+ &br_sslrec_in_gcm_vtable,
+ &br_sslrec_out_gcm_vtable);
+
+ /*
+ * Symmetric encryption:
+ * -- AES_128_CBC and AES_256_CBC require an "aes_cbc" implementation
+ * (actually two implementations, for encryption and decryption).
+ * -- 3DES_EDE_CBC requires a "des_cbc" implementation
+ * (actually two implementations, for encryption and decryption).
+ * -- AES_128_GCM and AES_256_GCM require an "aes_ctr" imeplementation
+ * and also a GHASH implementation.
+ *
+ * Two 3DES implementations are provided:
+ *
+ * des_tab Classical table-based implementation; it is
+ * not constant-time.
+ *
+ * dest_ct Constant-time DES/3DES implementation. It is
+ * slower than des_tab.
+ *
+ * Four AES implementations are provided:
+ *
+ * aes_ct Constant-time AES implementation, for 32-bit
+ * systems.
+ *
+ * aes_ct64 Constant-time AES implementation, for 64-bit
+ * systems. It actually also runs on 32-bit systems,
+ * but, on such systems, it yields larger code and
+ * slightly worse performance. On 64-bit systems,
+ * aes_ct64 is about twice faster than aes_ct for
+ * CTR processing (GCM encryption and decryption),
+ * and for CBC (decryption only).
+ *
+ * aes_small Smallest implementation provided, but also the
+ * slowest, and it is not constant-time. Use it
+ * only if desperate for code size.
+ *
+ * aes_big Classical table-based AES implementation. This
+ * is decently fast and still resonably compact,
+ * but it is not constant-time.
+ *
+ * Whether having constant-time implementations is absolutely
+ * required for security depends on the context (in particular
+ * whether the target architecture actually has cache memory),
+ * and while side-channel analysis for non-constant-time AES
+ * code has been demonstrated in lab conditions, it certainly
+ * does not apply to all actual usages, and it has never been
+ * spotted in the wild. It is still considered cautious to use
+ * constant-time code by default, and to consider the other
+ * implementations only if duly measured performance issues make
+ * it mandatory.
+ */
+ br_ssl_engine_set_aes_cbc(&cc->eng,
+ &br_aes_ct_cbcenc_vtable,
+ &br_aes_ct_cbcdec_vtable);
+ br_ssl_engine_set_aes_ctr(&cc->eng,
+ &br_aes_ct_ctr_vtable);
+ /* Alternate: aes_ct64
+ br_ssl_engine_set_aes_cbc(&cc->eng,
+ &br_aes_ct64_cbcenc_vtable,
+ &br_aes_ct64_cbcdec_vtable);
+ br_ssl_engine_set_aes_ctr(&cc->eng,
+ &br_aes_ct64_ctr_vtable);
+ */
+ /* Alternate: aes_small
+ br_ssl_engine_set_aes_cbc(&cc->eng,
+ &br_aes_small_cbcenc_vtable,
+ &br_aes_small_cbcdec_vtable);
+ br_ssl_engine_set_aes_ctr(&cc->eng,
+ &br_aes_small_ctr_vtable);
+ */
+ /* Alternate: aes_big
+ br_ssl_engine_set_aes_cbc(&cc->eng,
+ &br_aes_big_cbcenc_vtable,
+ &br_aes_big_cbcdec_vtable);
+ br_ssl_engine_set_aes_ctr(&cc->eng,
+ &br_aes_big_ctr_vtable);
+ */
+ br_ssl_engine_set_des_cbc(&cc->eng,
+ &br_des_ct_cbcenc_vtable,
+ &br_des_ct_cbcdec_vtable);
+ /* Alternate: des_tab
+ br_ssl_engine_set_des_cbc(&cc->eng,
+ &br_des_tab_cbcenc_vtable,
+ &br_des_tab_cbcdec_vtable);
+ */
+
+ /*
+ * GHASH is needed for AES_128_GCM and AES_256_GCM. Three
+ * implementations are provided:
+ *
+ * ctmul Uses 32-bit multiplications with a 64-bit result.
+ *
+ * ctmul32 Uses 32-bit multiplications with a 32-bit result.
+ *
+ * ctmul64 Uses 64-bit multiplications with a 64-bit result.
+ *
+ * On 64-bit platforms, ctmul64 is the smallest and fastest of
+ * the three. On 32-bit systems, ctmul should be prefered. The
+ * ctmul32 implementation is meant to be used for the specific
+ * 32-bit systems that do not have a 32x32->64 multiplier (i.e.
+ * the ARM Cortex-M0 and Cortex-M0+).
+ *
+ * These implementations are all constant-time as long as the
+ * underlying multiplication opcode is constant-time (which is
+ * true for all modern systems, but not for older architectures
+ * such that ARM9 or 80486).
+ */
+ br_ssl_engine_set_ghash(&cc->eng,
+ &br_ghash_ctmul);
+ /* Alternate: ghash_ctmul32
+ br_ssl_engine_set_ghash(&cc->eng,
+ &br_ghash_ctmul32);
+ */
+ /* Alternate: ghash_ctmul64
+ br_ssl_engine_set_ghash(&cc->eng,
+ &br_ghash_ctmul64);
+ */
+
+#if 0
+ /*
+ * For a client, the normal case is to validate the server
+ * certificate with regards to a set of trust anchors. This
+ * entails using a br_x509_minimal_context structure, configured
+ * with the relevant algorithms, as shown below.
+ *
+ * Alternatively, the client could "know" the intended server
+ * public key through an out-of-band mechanism, in which case
+ * a br_x509_knownkey_context is appropriate, for a much reduced
+ * code footprint.
+ *
+ * We assume here that the following extra parameters have been
+ * provided:
+ *
+ * xc engine context (br_x509_minimal_context *)
+ * trust_anchors trust anchors (br_x509_trust_anchor *)
+ * trust_anchors_num number of trust anchors (size_t)
+ */
+
+ /*
+ * The X.509 engine needs a hash function for processing the
+ * subject and issuer DN of certificates and trust anchors. Any
+ * supported hash function is appropriate; here we use SHA-256.
+ * The trust an
+ */
+ br_x509_minimal_init(xc, &br_sha256_vtable,
+ trust_anchors, trust_anchors_num);
+
+ /*
+ * Set suites and asymmetric crypto implementations. We use the
+ * "i31" code for RSA (it is somewhat faster than the "i32"
+ * implementation). These implementations are used for
+ * signature verification on certificates, but not for the
+ * SSL-specific usage of the server's public key. For instance,
+ * if the server has an EC public key but the rest of the chain
+ * (intermediate CA, root...) use RSA, then you would need only
+ * the RSA verification function below.
+ */
+ 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);
+
+ /*
+ * Set supported hash functions. These are for signatures on
+ * certificates. There again, you only need the hash functions
+ * that are actually used in certificates, but if a given
+ * function was included for the SSL engine, you may as well
+ * add it here.
+ *
+ * Note: the engine explicitly rejects signatures that use MD5.
+ * Thus, there is no need for MD5 here.
+ */
+ br_ssl_engine_set_hash(xc, br_sha1_ID, &br_sha1_vtable);
+ br_ssl_engine_set_hash(xc, br_sha224_ID, &br_sha224_vtable);
+ br_ssl_engine_set_hash(xc, br_sha256_ID, &br_sha256_vtable);
+ br_ssl_engine_set_hash(xc, br_sha384_ID, &br_sha384_vtable);
+ br_ssl_engine_set_hash(xc, br_sha512_ID, &br_sha512_vtable);
+
+ /*
+ * Link the X.509 engine in the SSL engine.
+ */
+ br_ssl_engine_set_x509(&cc->eng, &xc->vtable);
+#endif
+}
+
+/*
+ * Example server profile. Most of it is shared with the client
+ * profile, so see the comments in the client function for details.
+ *
+ * This example function assumes a server with a (unique) RSA private
+ * key, so the list of cipher suites is trimmed down for RSA.
+ */
+void
+example_server_profile(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_rsa_private_key *sk)
+{
+ static const uint16_t suites[] = {
+ BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ BR_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+ BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
+ BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ BR_TLS_RSA_WITH_AES_128_GCM_SHA256,
+ BR_TLS_RSA_WITH_AES_256_GCM_SHA384,
+ BR_TLS_RSA_WITH_AES_128_CBC_SHA256,
+ BR_TLS_RSA_WITH_AES_256_CBC_SHA256,
+ BR_TLS_RSA_WITH_AES_128_CBC_SHA,
+ BR_TLS_RSA_WITH_AES_256_CBC_SHA,
+ BR_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ BR_TLS_RSA_WITH_3DES_EDE_CBC_SHA
+ };
+
+ br_ssl_server_zero(cc);
+ br_ssl_engine_set_versions(&cc->eng, BR_TLS10, BR_TLS12);
+
+ br_ssl_engine_set_prf10(&cc->eng, &br_tls10_prf);
+ br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf);
+ br_ssl_engine_set_prf_sha384(&cc->eng, &br_tls12_sha384_prf);
+
+ /*
+ * Apart from the requirements listed in the client side, these
+ * hash functions are also used by the server to compute its
+ * signature on ECDHE parameters. Which functions are needed
+ * depends on what the client may support; furthermore, the
+ * client may fail to send the relevant extension, in which
+ * case the server will default to whatever it can (as per the
+ * standard, it should be SHA-1 in that case).
+ */
+ br_ssl_engine_set_hash(&cc->eng, br_md5_ID, &br_md5_vtable);
+ br_ssl_engine_set_hash(&cc->eng, br_sha1_ID, &br_sha1_vtable);
+ br_ssl_engine_set_hash(&cc->eng, br_sha224_ID, &br_sha224_vtable);
+ br_ssl_engine_set_hash(&cc->eng, br_sha256_ID, &br_sha256_vtable);
+ br_ssl_engine_set_hash(&cc->eng, br_sha384_ID, &br_sha384_vtable);
+ br_ssl_engine_set_hash(&cc->eng, br_sha512_ID, &br_sha512_vtable);
+
+ br_ssl_engine_set_suites(&cc->eng, suites,
+ (sizeof suites) / (sizeof suites[0]));
+
+ /*
+ * Elliptic curve implementation is used for ECDHE suites (but
+ * not for ECDH).
+ */
+ br_ssl_engine_set_ec(&cc->eng, &br_ec_prime_i31);
+
+ /*
+ * Set the "server policy": handler for the certificate chain
+ * and private key operations. Here, we indicate that the RSA
+ * private key is fit for both signing and decrypting, and we
+ * provide the two relevant implementations.
+
+ * BR_KEYTYPE_KEYX allows TLS_RSA_*, BR_KEYTYPE_SIGN allows
+ * TLS_ECDHE_RSA_*.
+ */
+ br_ssl_server_set_single_rsa(cc, chain, chain_len, sk,
+ BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN,
+ br_rsa_i31_private, br_rsa_i31_pkcs1_sign);
+ /*
+ * If the server used an EC private key, this call would look
+ * like this:
+
+ br_ssl_server_set_single_ec(cc, chain, chain_len, sk,
+ BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN,
+ cert_issuer_key_type,
+ &br_ec_prime_i31, br_ecdsa_i31_sign_asn1);
+
+ * Note the tricky points:
+ *
+ * -- "ECDH" cipher suites use only the EC code (&br_ec_prime_i31);
+ * the ECDHE_ECDSA cipher suites need both the EC code and
+ * the ECDSA signature implementation.
+ *
+ * -- For "ECDH" (not "ECDHE") cipher suites, the engine must
+ * know the key type (RSA or EC) for the intermediate CA that
+ * issued the server's certificate; this is an artefact of
+ * how the protocol is defined. BearSSL won't try to decode
+ * the server's certificate to obtain that information (it
+ * could do that, the code is there, but it would increase the
+ * footprint). So this must be provided by the caller.
+ *
+ * -- BR_KEYTYPE_KEYX allows ECDH, BR_KEYTYPE_SIGN allows
+ * ECDHE_ECDSA.
+ */
+
+ br_ssl_engine_set_cbc(&cc->eng,
+ &br_sslrec_in_cbc_vtable,
+ &br_sslrec_out_cbc_vtable);
+ br_ssl_engine_set_gcm(&cc->eng,
+ &br_sslrec_in_gcm_vtable,
+ &br_sslrec_out_gcm_vtable);
+
+ br_ssl_engine_set_aes_cbc(&cc->eng,
+ &br_aes_ct_cbcenc_vtable,
+ &br_aes_ct_cbcdec_vtable);
+ br_ssl_engine_set_aes_ctr(&cc->eng,
+ &br_aes_ct_ctr_vtable);
+ /* Alternate: aes_ct64
+ br_ssl_engine_set_aes_cbc(&cc->eng,
+ &br_aes_ct64_cbcenc_vtable,
+ &br_aes_ct64_cbcdec_vtable);
+ br_ssl_engine_set_aes_ctr(&cc->eng,
+ &br_aes_ct64_ctr_vtable);
+ */
+ /* Alternate: aes_small
+ br_ssl_engine_set_aes_cbc(&cc->eng,
+ &br_aes_small_cbcenc_vtable,
+ &br_aes_small_cbcdec_vtable);
+ br_ssl_engine_set_aes_ctr(&cc->eng,
+ &br_aes_small_ctr_vtable);
+ */
+ /* Alternate: aes_big
+ br_ssl_engine_set_aes_cbc(&cc->eng,
+ &br_aes_big_cbcenc_vtable,
+ &br_aes_big_cbcdec_vtable);
+ br_ssl_engine_set_aes_ctr(&cc->eng,
+ &br_aes_big_ctr_vtable);
+ */
+ br_ssl_engine_set_des_cbc(&cc->eng,
+ &br_des_ct_cbcenc_vtable,
+ &br_des_ct_cbcdec_vtable);
+ /* Alternate: des_tab
+ br_ssl_engine_set_des_cbc(&cc->eng,
+ &br_des_tab_cbcenc_vtable,
+ &br_des_tab_cbcdec_vtable);
+ */
+
+ br_ssl_engine_set_ghash(&cc->eng,
+ &br_ghash_ctmul);
+ /* Alternate: ghash_ctmul32
+ br_ssl_engine_set_ghash(&cc->eng,
+ &br_ghash_ctmul32);
+ */
+ /* Alternate: ghash_ctmul64
+ br_ssl_engine_set_ghash(&cc->eng,
+ &br_ghash_ctmul64);
+ */
+}
--- /dev/null
+/*
+ * 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 "bearssl.h"
+
+/*
+ * The private key for the server certificate (EC).
+ */
+
+static const unsigned char EC_X[] = {
+ 0x03, 0x91, 0x5B, 0x42, 0x06, 0x90, 0x73, 0x91, 0x1B, 0x48, 0xEF, 0x08,
+ 0xFB, 0xB5, 0xAD, 0x75, 0x65, 0xF9, 0xE6, 0xF7, 0x21, 0x47, 0x62, 0x48,
+ 0xFA, 0x3F, 0x97, 0x7B, 0x70, 0x9D, 0x86, 0xA5
+};
+
+static const br_ec_private_key EC = {
+ 23,
+ (unsigned char *)EC_X, sizeof EC_X
+};
--- /dev/null
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIAORW0IGkHORG0jvCPu1rXVl+eb3IUdiSPo/l3twnYaloAoGCCqGSM49AwEHoUQDQgAE
+Xzidp/9Niq/2NDlGGvw63/Qjqqnq+8UI3gCOvnmlN1hMbd0ByqtH34m2xxcfOPwdIBTdRcDgj5NO
+OAv86ZmhSQ==
+-----END EC PRIVATE KEY-----
--- /dev/null
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEA1HodJ7orOmeykWr754NEyu0cda3dTYNi1qpolbIkIXsVriqZaBXtZvC4WOfT
+9S7G2Spe5w4u5/xnWcDIYX1LpG/dn9nIhYdkx7oaDynUlqh4mmtiIKky0O6pjChhR6JQKmP2Id7a
+2NXwf8UAgnDmo79ciSdPUZJ3A8OwzC477CPyL1NBr4mT/9KAsUOX3tYZoJISej1meeHBvOF3cKKL
+PUaEUz/kTkJBN5IeH/04s/fvhzmA01bP9OAT3mSwcqQDhMRB7W/6PuLKBCDS19wsgit64m2hHEjb
+z4lPNJc9KKhT2ufB4XMVozB2f48jQhQ9UTTSWq08m8vI/n9ujkDzvQIDAQABAoIBADzb40jzQpl+
+hT+wsIl96HDlXI76Z1Zh6SgKdF1YQpASdMHHstwE19Rx46OXd3cVWGBwifFNdzL8cU/cb6i43jcx
+0X2NQCm6/6tTi05HkXw7shus4VTwkb0VdxvNnxuJCsQxkJjf/7g3AyVdtIkoNG+3ipZAW7BGLu+1
+mAjLv18h4LniI8JGWQK75z8xNQzEdOFVyqC1PujjC5emesxlRW8Ks+MzQ+20WTpHGkLAoLJZJ1XE
+bDQqFbkRXu4imKLtA4iyBrEpXEKZR85tVO+NQOGdPyH/ugK23nSDcJlI2PTHSlGABTpZZUmigO4O
+b8lppU7cFa2JemKG3kEj0BWDOWMCgYEA+fYynFHXcbJi7YEk2vapLMMtVZSVUeU2Ep4uH47YIiJk
+XqP8YPAU3BBIb08afcw3Iyd2tjGq3nDJ7KsKUPHqeXl0vjurLmOXom8KRXvXbNJtG3AxA68miyjF
++ElnRUHx0zUFJyp5IdoGtj2i6DxA+m/E/PXEBeuaMapAfl7uIlsCgYEA2Zwa3JRR9sGW2g4RPzco
+ejOwxL7faCvTHGVnejyvWVCrKTYXORVxl2LdzSXujf8mj3Ehvo+chU464STH4Urf0GCzxEQurHMW
+XwfJOnNe2pvu4rSpPTMUe+6n1Kz3U+Y+8IVXTIuWG93XNvyJN1l1lnWLLvcELSmJ2befcTvi7ccC
+gYEA5PwCLyvWRwTZFaRaI/EU17nRHPYpuEVXPMUFkclk/BgvhHeLay5knZiZEscPiLB8zkqHuK5V
+TsNaZ+HkaHTFjRSTuvWkgrGfpqE8cpzZo4o9g4ZKkIpyr8bhXOu5nDumEgsfNlr1bupxfZ+HTmJs
+UD/14JowQhAsSFUkEeBbHMMCgYEAjazgoDPAmVK4kAcQm4Ohys3UjINomD3QGHC8ygywbQnkJdSd
+kgCwD8vCdEn54mD4DfOt8I83bGLeWq7Do55H0TbkUyfA622SZxR+optyagmToe3VMY8MCxP6GLDz
+5Z/F4notuBw5ArOP5rDL9Uk9EVQ95bnU8kJVCXZPTD2dJQkCgYByDKfPBpVp9HUgNAPgz5pRk/VC
+LvKFvs5POLWMoplC871lOOI0PyGd9b2zv3M8GN728H+hwlXyOOkOHjHn21HFcY1ncTqfVVJg7kX2
+CJiBt3sv8pZ9c9Cmq6qDSUE1qZBnztO5c1SqhACIiJAdhpvluM6JChtHYjHCP8OMhgk8hg==
+-----END RSA PRIVATE KEY-----
--- /dev/null
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIEJOkvo4MZ9N+wlTodEzmWor1RauybudPe92K15viDbzoAoGCCqGSM49AwEHoUQDQgAE
+cC6SggEXbG2r4dFjCUhJ0qY1UtM8c7uyiDeYh/GN4Oxlmg4T9e2RYci2bTOEbq6OVYDNSZ4Hv9Cu
+nebQsycWoQ==
+-----END EC PRIVATE KEY-----
--- /dev/null
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAs+hrr5wWUuOBDFCrJc7MDcfyH39Q3yxcNdZiLmMnQafkU6hLJ/oTkaP6CUov
+O17Pd7OKwc1JlZx1DWR07+TXS7mhm2jSMHFI6vdLFN8/R6nYu+yPKMz637QflHyW/AgFKPno9C8v
+7mKcijrghVhgtg8tMLTAQVSRTB9frfEZ8MAipn3YP3k0WUJ7W7VBxGR/Us88NyKhL3kllCRBwj/6
+x3X7SLUNGKf0VPMubthDWMSrUOgFrZG2HgF1s1Sc3qCZFfus8VyXSVHM71gSb3NrszQUAQ9anfqq
+1pPT4urDq7xO7cxRobj4lLa0LKiGKx/2UUMpUl4TibNqeGBOTsAbpQIDAQABAoIBAAtBpQ85SGpK
+QsZG+9ZjQIAyPPN8j05PY7uYnM8DNC8W9qHHW2B2dKf9pwTSx+7CiV+Xc7yZgBukzOwYF3r1CgV6
+aWKkZdZTGDlfXKrDJx3wQhfL/s8SODYr+nfbbcT6KXx9WnaAx1J2iA3cDjU5qN9rRqwP+yF7TZYC
+NoXXGoTmHb7gj1H1IJNdiUgG0netXpM2HydRLzwHDweKav6sm4V4TTeHPYokVp8W7lL7xRhwQXVD
+lcE1noY5NczXV88k9n0EbqGDwX3pJoDC/xWzBFh/+oupxotM4KY2dKJGmtKTmiIef3u43CPv5SYh
+V2OcEXn+joV5qHGhg6yN+ri0/ucCgYEA4x2NBFNtbpx3lmc2r2hwfbawcTVKKlxqJWdoG2bd7HQz
+bO+uqtxhLOxEou4S9uPUVylvpNlDs3xQ+DF9p8oTo5XlHvA6DT/cAjWSQ+MRHqCV30T0lDSd0McZ
+4PaV1nq94bGuPVrGe/Dex5dL+VVhn2tpoqwudsyx5hHA8hFE1zcCgYEAysnhrQa1HZQ0hOaA2c/e
+A8I47dEIyGi4N6uJVBUMM1ecKifs4FKybOtI+XM3mwuAXUyVQGi2SZBBpE4bN3oUDWGwYF7SAJV0
+JJHpBxlZBvYRC7Vfh8HFPYIQCynP0Q4BeQVDaCPW3puJsTWnn2lNhT/PsSm3v76JwTRrBoqaGgMC
+gYAwyyiAxWu9V+BZb9NP3CBO4fEGYWyNrU0gvBahzHfhVRW3Ucc07iPygtA8MOniIRB9qWlTAVqK
+NSswJ3HXmpKdkpanDvVp405hKyFBdIc5DUclsKrbLHK7aAsnSdLnQXeKBaJpjBcYiadTOi4YYz+W
+AH2xdUyGOXP++dF6MDuaAQKBgQCtWyHygW5pR94R0t9J1FpuCiYSn4ULlgINjTXLzGZuqbGVlCX6
+qpdfZ1At92IMyCtHFwXsVtemUYzcAe1gYpsryVw3Njf+ScVM0fNMn02tFsQBp15wNqT/7OT8NhUz
+GO8HXwl9yE2SZZKzDDQsoZ+kjqVlRU2QvDkVElN/9xK/swKBgDz6m4XHvhvITo2bd8/i4FxTN1gr
+napgAc2DHOzCmeyYCjKvZAJDLeNleni1kj1UfrzVrH2BFM38asRJu8xPI4WjfH1fFktNjXVu6Ctk
+YFu0/0TlWkzowZHmE/K0M0tuJLt42m/DLW8deMyl38x+PUPUZb4OdVAKAua/voOMZtQw
+-----END RSA PRIVATE KEY-----
--- /dev/null
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEINx41f6h/utlj52XNFbIGJdkF3qZy1/g9hH2/yV4t/tnoAoGCCqGSM49AwEHoUQDQgAE
+cXS6q7kwLoHV5Vf58yBoDJz5ZNu0IA1t6kDQSm5C/baaaCVE9t97xPze3Xu7xdt8dj9BZkBu26eH
+wuXYxfN/jQ==
+-----END EC PRIVATE KEY-----
--- /dev/null
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAttk01FD9s696c/HOOL9db0Xh/U6xmMZggybSF9HFt5qjwd5jOZec8F5cyBwX
+uYgZbfC2LjBQoVRuk8DbzzDLnx4nefHDmVI1qj2237CtfMtJzcDt52YQKunOKB8hUPp3TC3a7zxY
+606/zun7Gtqjg6PNo8qTgNza8xfMeqszgJyy1H9GP8U83GGUtycpbiq8Wwk21MY7Deu+ztsdHLwQ
+anFxs/LKKJp38orsQu+xSo7i8hoyKs3ApkYsmsKFN5F/RqGTgaF0Zt+6szkgkZP6HaGohefk+Qf2
+EPaoJwG2fxLDQMPJ4rCrSRg6ZLZZt5W1ljbfImmqcmpUTicpow6XFQIDAQABAoIBAENjavKDBPWn
+yygXKqtEb/GWHlNmoNKO7jv33z9TGxzvW8IULZqos3jtNiG0JNRGgiTALcx5FwZWYUiIMBq8v5bd
+nKv3O+DyaP/crdzkNxRCsekoXSXGuleugsHLs1IudTA4yDMamSTkCZH/LwH3KYNXJ+9hNhqsiu9D
+yqM9HIad2k/hmVFv4NDdH3VWqsQJFfrGEXgKRJKNpuzKeST3oo4iLcwH9NGiKXfjW23ekOiLYFwZ
+q8Yd6tOgNLpGuDWk9rlXPJALyXFZ/3UXZaKU5f0ZRfPfMQgM8toeWeWJS0FW7g6aLCJATsfOu/II
+j3nTVCPryvGF4mwe/y+Rgbd67xMCgYEA3Wpiac27hvbLzwbSTWYsKql5uKV0HTim3haNDuzMHJVY
+ZRJSuTY+rZBoaiuDRKMCMI3dQM8AZUJfHQclyTxjtn17Ig8cTKMN6Wr2MRTBplCq3wNLVjbOPAE2
+cv74gUfgpRLdlyueYO7j6PcTS+l41+wB1A/zAEm346Eoxoztt5cCgYEA02ipYQFX4T+8BSkcEyzP
+qeMT9d3BLPm4tTeq2sXRgcfEbF/ENcAX9OfPSEx4kVtzsfJXma5/dg0fuVgl1hO5WLBT+L6MJ/A2
+sGX3Y7x+doXI0xcNd/Epr7oWqZuCO7477vzJcNtud/KQJj2EmRNaHKKtaohqO5dnNhsM540lnDMC
+gYBU40KT2eJ5ngkJeE4Mio2IVa1rE1PvGBcxsmemPzcKBl/7cAjzJU7mcCT3/3K2T+C5CMq43CQE
+rmuUz3a3LkX0YytgJXbuEt10jiORMaoEv4yjL7okdaKf8r8TW5mexxXjc9Ys7PYtp6kNWhy1z+8a
+qUsSKIM7qwerZ9AgP0usRQKBgQDEHy4y/coG/tdweii/aSzlT/Huf2B8VtaR1yi7eBTaLvb8CwO9
+UY1n970GN1sKjiqQhF/cBFPesmIh0bKYHQgvTLU555uiWWiC0LVmYzF2xrn9ij9GbAXeLeZkRg3V
+Wq/DD+PYvNiIkhBESYG/eIJ6WjhCwna6/cQUH5gjH4AqnQKBgQCsKyjLtx+FeFu7PZ8AgCGWRVvs
+suxB74pxlMqMgBbBHyAGQOTTuaaTr/gwNXAAErAXS1X9VsAcAkM/yFv19mdZmJQG9vUMOe48AZDB
+c7xt3t3Ul71eAlbAYkrQGtq64yO3w7ny4C7GUVqMX03XwKToCrXqeKfGwrZGNP+lgZYrbw==
+-----END RSA PRIVATE KEY-----
--- /dev/null
+/*
+ * 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 "bearssl.h"
+
+/*
+ * The private key for the server certificate (RSA).
+ */
+
+static const unsigned char RSA_P[] = {
+ 0xF9, 0xF6, 0x32, 0x9C, 0x51, 0xD7, 0x71, 0xB2, 0x62, 0xED, 0x81, 0x24,
+ 0xDA, 0xF6, 0xA9, 0x2C, 0xC3, 0x2D, 0x55, 0x94, 0x95, 0x51, 0xE5, 0x36,
+ 0x12, 0x9E, 0x2E, 0x1F, 0x8E, 0xD8, 0x22, 0x22, 0x64, 0x5E, 0xA3, 0xFC,
+ 0x60, 0xF0, 0x14, 0xDC, 0x10, 0x48, 0x6F, 0x4F, 0x1A, 0x7D, 0xCC, 0x37,
+ 0x23, 0x27, 0x76, 0xB6, 0x31, 0xAA, 0xDE, 0x70, 0xC9, 0xEC, 0xAB, 0x0A,
+ 0x50, 0xF1, 0xEA, 0x79, 0x79, 0x74, 0xBE, 0x3B, 0xAB, 0x2E, 0x63, 0x97,
+ 0xA2, 0x6F, 0x0A, 0x45, 0x7B, 0xD7, 0x6C, 0xD2, 0x6D, 0x1B, 0x70, 0x31,
+ 0x03, 0xAF, 0x26, 0x8B, 0x28, 0xC5, 0xF8, 0x49, 0x67, 0x45, 0x41, 0xF1,
+ 0xD3, 0x35, 0x05, 0x27, 0x2A, 0x79, 0x21, 0xDA, 0x06, 0xB6, 0x3D, 0xA2,
+ 0xE8, 0x3C, 0x40, 0xFA, 0x6F, 0xC4, 0xFC, 0xF5, 0xC4, 0x05, 0xEB, 0x9A,
+ 0x31, 0xAA, 0x40, 0x7E, 0x5E, 0xEE, 0x22, 0x5B
+};
+
+static const unsigned char RSA_Q[] = {
+ 0xD9, 0x9C, 0x1A, 0xDC, 0x94, 0x51, 0xF6, 0xC1, 0x96, 0xDA, 0x0E, 0x11,
+ 0x3F, 0x37, 0x28, 0x7A, 0x33, 0xB0, 0xC4, 0xBE, 0xDF, 0x68, 0x2B, 0xD3,
+ 0x1C, 0x65, 0x67, 0x7A, 0x3C, 0xAF, 0x59, 0x50, 0xAB, 0x29, 0x36, 0x17,
+ 0x39, 0x15, 0x71, 0x97, 0x62, 0xDD, 0xCD, 0x25, 0xEE, 0x8D, 0xFF, 0x26,
+ 0x8F, 0x71, 0x21, 0xBE, 0x8F, 0x9C, 0x85, 0x4E, 0x3A, 0xE1, 0x24, 0xC7,
+ 0xE1, 0x4A, 0xDF, 0xD0, 0x60, 0xB3, 0xC4, 0x44, 0x2E, 0xAC, 0x73, 0x16,
+ 0x5F, 0x07, 0xC9, 0x3A, 0x73, 0x5E, 0xDA, 0x9B, 0xEE, 0xE2, 0xB4, 0xA9,
+ 0x3D, 0x33, 0x14, 0x7B, 0xEE, 0xA7, 0xD4, 0xAC, 0xF7, 0x53, 0xE6, 0x3E,
+ 0xF0, 0x85, 0x57, 0x4C, 0x8B, 0x96, 0x1B, 0xDD, 0xD7, 0x36, 0xFC, 0x89,
+ 0x37, 0x59, 0x75, 0x96, 0x75, 0x8B, 0x2E, 0xF7, 0x04, 0x2D, 0x29, 0x89,
+ 0xD9, 0xB7, 0x9F, 0x71, 0x3B, 0xE2, 0xED, 0xC7
+};
+
+static const unsigned char RSA_DP[] = {
+ 0xE4, 0xFC, 0x02, 0x2F, 0x2B, 0xD6, 0x47, 0x04, 0xD9, 0x15, 0xA4, 0x5A,
+ 0x23, 0xF1, 0x14, 0xD7, 0xB9, 0xD1, 0x1C, 0xF6, 0x29, 0xB8, 0x45, 0x57,
+ 0x3C, 0xC5, 0x05, 0x91, 0xC9, 0x64, 0xFC, 0x18, 0x2F, 0x84, 0x77, 0x8B,
+ 0x6B, 0x2E, 0x64, 0x9D, 0x98, 0x99, 0x12, 0xC7, 0x0F, 0x88, 0xB0, 0x7C,
+ 0xCE, 0x4A, 0x87, 0xB8, 0xAE, 0x55, 0x4E, 0xC3, 0x5A, 0x67, 0xE1, 0xE4,
+ 0x68, 0x74, 0xC5, 0x8D, 0x14, 0x93, 0xBA, 0xF5, 0xA4, 0x82, 0xB1, 0x9F,
+ 0xA6, 0xA1, 0x3C, 0x72, 0x9C, 0xD9, 0xA3, 0x8A, 0x3D, 0x83, 0x86, 0x4A,
+ 0x90, 0x8A, 0x72, 0xAF, 0xC6, 0xE1, 0x5C, 0xEB, 0xB9, 0x9C, 0x3B, 0xA6,
+ 0x12, 0x0B, 0x1F, 0x36, 0x5A, 0xF5, 0x6E, 0xEA, 0x71, 0x7D, 0x9F, 0x87,
+ 0x4E, 0x62, 0x6C, 0x50, 0x3F, 0xF5, 0xE0, 0x9A, 0x30, 0x42, 0x10, 0x2C,
+ 0x48, 0x55, 0x24, 0x11, 0xE0, 0x5B, 0x1C, 0xC3
+};
+
+static const unsigned char RSA_DQ[] = {
+ 0x8D, 0xAC, 0xE0, 0xA0, 0x33, 0xC0, 0x99, 0x52, 0xB8, 0x90, 0x07, 0x10,
+ 0x9B, 0x83, 0xA1, 0xCA, 0xCD, 0xD4, 0x8C, 0x83, 0x68, 0x98, 0x3D, 0xD0,
+ 0x18, 0x70, 0xBC, 0xCA, 0x0C, 0xB0, 0x6D, 0x09, 0xE4, 0x25, 0xD4, 0x9D,
+ 0x92, 0x00, 0xB0, 0x0F, 0xCB, 0xC2, 0x74, 0x49, 0xF9, 0xE2, 0x60, 0xF8,
+ 0x0D, 0xF3, 0xAD, 0xF0, 0x8F, 0x37, 0x6C, 0x62, 0xDE, 0x5A, 0xAE, 0xC3,
+ 0xA3, 0x9E, 0x47, 0xD1, 0x36, 0xE4, 0x53, 0x27, 0xC0, 0xEB, 0x6D, 0x92,
+ 0x67, 0x14, 0x7E, 0xA2, 0x9B, 0x72, 0x6A, 0x09, 0x93, 0xA1, 0xED, 0xD5,
+ 0x31, 0x8F, 0x0C, 0x0B, 0x13, 0xFA, 0x18, 0xB0, 0xF3, 0xE5, 0x9F, 0xC5,
+ 0xE2, 0x7A, 0x2D, 0xB8, 0x1C, 0x39, 0x02, 0xB3, 0x8F, 0xE6, 0xB0, 0xCB,
+ 0xF5, 0x49, 0x3D, 0x11, 0x54, 0x3D, 0xE5, 0xB9, 0xD4, 0xF2, 0x42, 0x55,
+ 0x09, 0x76, 0x4F, 0x4C, 0x3D, 0x9D, 0x25, 0x09
+};
+
+static const unsigned char RSA_IQ[] = {
+ 0x72, 0x0C, 0xA7, 0xCF, 0x06, 0x95, 0x69, 0xF4, 0x75, 0x20, 0x34, 0x03,
+ 0xE0, 0xCF, 0x9A, 0x51, 0x93, 0xF5, 0x42, 0x2E, 0xF2, 0x85, 0xBE, 0xCE,
+ 0x4F, 0x38, 0xB5, 0x8C, 0xA2, 0x99, 0x42, 0xF3, 0xBD, 0x65, 0x38, 0xE2,
+ 0x34, 0x3F, 0x21, 0x9D, 0xF5, 0xBD, 0xB3, 0xBF, 0x73, 0x3C, 0x18, 0xDE,
+ 0xF6, 0xF0, 0x7F, 0xA1, 0xC2, 0x55, 0xF2, 0x38, 0xE9, 0x0E, 0x1E, 0x31,
+ 0xE7, 0xDB, 0x51, 0xC5, 0x71, 0x8D, 0x67, 0x71, 0x3A, 0x9F, 0x55, 0x52,
+ 0x60, 0xEE, 0x45, 0xF6, 0x08, 0x98, 0x81, 0xB7, 0x7B, 0x2F, 0xF2, 0x96,
+ 0x7D, 0x73, 0xD0, 0xA6, 0xAB, 0xAA, 0x83, 0x49, 0x41, 0x35, 0xA9, 0x90,
+ 0x67, 0xCE, 0xD3, 0xB9, 0x73, 0x54, 0xAA, 0x84, 0x00, 0x88, 0x88, 0x90,
+ 0x1D, 0x86, 0x9B, 0xE5, 0xB8, 0xCE, 0x89, 0x0A, 0x1B, 0x47, 0x62, 0x31,
+ 0xC2, 0x3F, 0xC3, 0x8C, 0x86, 0x09, 0x3C, 0x86
+};
+
+static const br_rsa_private_key RSA = {
+ 2048,
+ (unsigned char *)RSA_P, sizeof RSA_P,
+ (unsigned char *)RSA_Q, sizeof RSA_Q,
+ (unsigned char *)RSA_DP, sizeof RSA_DP,
+ (unsigned char *)RSA_DQ, sizeof RSA_DQ,
+ (unsigned char *)RSA_IQ, sizeof RSA_IQ
+};
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+
+#include "bearssl.h"
+
+/*
+ * This sample code can use three possible certificate chains:
+ * -- A full-RSA chain (server key is RSA, certificates are signed with RSA)
+ * -- A full-EC chain (server key is EC, certificates are signed with ECDSA)
+ * -- A mixed chain (server key is EC, certificates are signed with RSA)
+ *
+ * The macros below define which chain is selected. This impacts the list
+ * of supported cipher suites.
+ */
+
+#if !(SERVER_RSA || SERVER_EC || SERVER_MIXED)
+#define SERVER_RSA 1
+#define SERVER_EC 0
+#define SERVER_MIXED 0
+#endif
+
+#if SERVER_RSA
+#include "chain-rsa.h"
+#include "key-rsa.h"
+#define SKEY RSA
+#elif SERVER_EC
+#include "chain-ec.h"
+#include "key-ec.h"
+#define SKEY EC
+#elif SERVER_MIXED
+#include "chain-ec+rsa.h"
+#include "key-ec.h"
+#define SKEY EC
+#else
+#error Must use one of RSA, EC or MIXED chains.
+#endif
+
+/*
+ * Create a server socket bound to the specified host and port. If 'host'
+ * is NULL, this will bind "generically" (all addresses).
+ *
+ * Returned value is the server socket descriptor, or -1 on error.
+ */
+static int
+host_bind(const char *host, const char *port)
+{
+ struct addrinfo hints, *si, *p;
+ int fd;
+ int err;
+
+ memset(&hints, 0, sizeof hints);
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ err = getaddrinfo(host, port, &hints, &si);
+ if (err != 0) {
+ fprintf(stderr, "ERROR: getaddrinfo(): %s\n",
+ gai_strerror(err));
+ return -1;
+ }
+ fd = -1;
+ for (p = si; p != NULL; p = p->ai_next) {
+ struct sockaddr *sa;
+ struct sockaddr_in sa4;
+ struct sockaddr_in6 sa6;
+ size_t sa_len;
+ void *addr;
+ char tmp[INET6_ADDRSTRLEN + 50];
+ int opt;
+
+ sa = (struct sockaddr *)p->ai_addr;
+ if (sa->sa_family == AF_INET) {
+ sa4 = *(struct sockaddr_in *)sa;
+ sa = (struct sockaddr *)&sa4;
+ sa_len = sizeof sa4;
+ addr = &sa4.sin_addr;
+ if (host == NULL) {
+ sa4.sin_addr.s_addr = INADDR_ANY;
+ }
+ } else if (sa->sa_family == AF_INET6) {
+ sa6 = *(struct sockaddr_in6 *)sa;
+ sa = (struct sockaddr *)&sa6;
+ sa_len = sizeof sa6;
+ addr = &sa6.sin6_addr;
+ if (host == NULL) {
+ sa6.sin6_addr = in6addr_any;
+ }
+ } else {
+ addr = NULL;
+ sa_len = p->ai_addrlen;
+ }
+ if (addr != NULL) {
+ inet_ntop(p->ai_family, addr, tmp, sizeof tmp);
+ } else {
+ sprintf(tmp, "<unknown family: %d>",
+ (int)sa->sa_family);
+ }
+ fprintf(stderr, "binding to: %s\n", tmp);
+ fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
+ if (fd < 0) {
+ perror("socket()");
+ continue;
+ }
+ opt = 1;
+ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof opt);
+ opt = 0;
+ setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof opt);
+ if (bind(fd, sa, sa_len) < 0) {
+ perror("bind()");
+ close(fd);
+ continue;
+ }
+ break;
+ }
+ if (p == NULL) {
+ freeaddrinfo(si);
+ fprintf(stderr, "ERROR: failed to bind\n");
+ return -1;
+ }
+ freeaddrinfo(si);
+ if (listen(fd, 5) < 0) {
+ perror("listen()");
+ close(fd);
+ return -1;
+ }
+ fprintf(stderr, "bound.\n");
+ return fd;
+}
+
+/*
+ * Accept a single client on the provided server socket. This is blocking.
+ * On error, this returns -1.
+ */
+static int
+accept_client(int server_fd)
+{
+ int fd;
+ struct sockaddr sa;
+ socklen_t sa_len;
+ char tmp[INET6_ADDRSTRLEN + 50];
+ const char *name;
+
+ sa_len = sizeof sa;
+ fd = accept(server_fd, &sa, &sa_len);
+ if (fd < 0) {
+ perror("accept()");
+ return -1;
+ }
+ name = NULL;
+ switch (sa.sa_family) {
+ case AF_INET:
+ name = inet_ntop(AF_INET,
+ &((struct sockaddr_in *)&sa)->sin_addr,
+ tmp, sizeof tmp);
+ break;
+ case AF_INET6:
+ name = inet_ntop(AF_INET,
+ &((struct sockaddr_in *)&sa)->sin_addr,
+ tmp, sizeof tmp);
+ break;
+ }
+ if (name == NULL) {
+ sprintf(tmp, "<unknown: %lu>", (unsigned long)sa.sa_family);
+ name = tmp;
+ }
+ fprintf(stderr, "accepting connection from: %s\n", name);
+ return fd;
+}
+
+/*
+ * Low-level data read callback for the simplified SSL I/O API.
+ */
+static int
+sock_read(void *ctx, unsigned char *buf, size_t len)
+{
+ for (;;) {
+ ssize_t rlen;
+
+ rlen = read(*(int *)ctx, buf, len);
+ if (rlen <= 0) {
+ if (rlen < 0 && errno == EINTR) {
+ continue;
+ }
+ return -1;
+ }
+ return (int)rlen;
+ }
+}
+
+/*
+ * Low-level data write callback for the simplified SSL I/O API.
+ */
+static int
+sock_write(void *ctx, const unsigned char *buf, size_t len)
+{
+ for (;;) {
+ ssize_t wlen;
+
+ wlen = write(*(int *)ctx, buf, len);
+ if (wlen <= 0) {
+ if (wlen < 0 && errno == EINTR) {
+ continue;
+ }
+ return -1;
+ }
+ return (int)wlen;
+ }
+}
+
+/*
+ * Sample HTTP response to send.
+ */
+static const char *HTTP_RES =
+ "HTTP/1.0 200 OK\r\n"
+ "Content-Length: 46\r\n"
+ "Connection: close\r\n"
+ "Content-Type: text/html; charset=iso-8859-1\r\n"
+ "\r\n"
+ "<html>\r\n"
+ "<body>\r\n"
+ "<p>Test!</p>\r\n"
+ "</body>\r\n"
+ "</html>\r\n";
+
+/*
+ * Main program: this is a simple program that expects 1 argument: a
+ * port number. This will start a simple network server on that port,
+ * that expects incoming SSL clients. It handles only one client at a
+ * time (handling several would require threads, sub-processes, or
+ * multiplexing with select()/poll(), all of which being possible).
+ *
+ * For each client, the server will wait for two successive newline
+ * characters (ignoring CR characters, so CR+LF is accepted), then
+ * produce a sample static HTTP response. This is very crude, but
+ * sufficient for explanatory purposes.
+ */
+int
+main(int argc, char *argv[])
+{
+ const char *port;
+ int fd;
+
+ if (argc != 2) {
+ return EXIT_FAILURE;
+ }
+ port = argv[1];
+
+ /*
+ * Open the server socket.
+ */
+ fd = host_bind(NULL, port);
+ if (fd < 0) {
+ return EXIT_FAILURE;
+ }
+
+ /*
+ * Process each client, one at a time.
+ */
+ for (;;) {
+ int cfd;
+ br_ssl_server_context sc;
+ unsigned char iobuf[BR_SSL_BUFSIZE_BIDI];
+ br_sslio_context ioc;
+ int lcwn, err;
+
+ cfd = accept_client(fd);
+ if (cfd < 0) {
+ return EXIT_FAILURE;
+ }
+
+ /*
+ * Initialise the context with the cipher suites and
+ * algorithms. This depends on the server key type
+ * (and, for EC keys, the signature algorithm used by
+ * the CA to sign the server's certificate).
+ *
+ * Depending on the defined macros, we may select one of
+ * the "minimal" profiles. Key exchange algorithm depends
+ * on the key type:
+ * RSA key: RSA or ECDHE_RSA
+ * EC key, cert signed with ECDSA: ECDH_ECDSA or ECDHE_ECDSA
+ * EC key, cert signed with RSA: ECDH_RSA or ECDHE_ECDSA
+ */
+#if SERVER_RSA
+#if SERVER_PROFILE_MIN_FS
+ br_ssl_server_init_mine2g(&sc, CHAIN, CHAIN_LEN, &SKEY);
+#elif SERVER_PROFILE_MIN_NOFS
+ br_ssl_server_init_minr2g(&sc, CHAIN, CHAIN_LEN, &SKEY);
+#else
+ br_ssl_server_init_full_rsa(&sc, CHAIN, CHAIN_LEN, &SKEY);
+#endif
+#elif SERVER_EC
+#if SERVER_PROFILE_MIN_FS
+ br_ssl_server_init_minf2g(&sc, CHAIN, CHAIN_LEN, &SKEY);
+#elif SERVER_PROFILE_MIN_NOFS
+ br_ssl_server_init_minv2g(&sc, CHAIN, CHAIN_LEN, &SKEY);
+#else
+ br_ssl_server_init_full_ec(&sc, CHAIN, CHAIN_LEN,
+ BR_KEYTYPE_EC, &SKEY);
+#endif
+#else /* SERVER_MIXED */
+#if SERVER_PROFILE_MIN_FS
+ br_ssl_server_init_minf2g(&sc, CHAIN, CHAIN_LEN, &SKEY);
+#elif SERVER_PROFILE_MIN_NOFS
+ br_ssl_server_init_minu2g(&sc, CHAIN, CHAIN_LEN, &SKEY);
+#else
+ br_ssl_server_init_full_ec(&sc, CHAIN, CHAIN_LEN,
+ BR_KEYTYPE_RSA, &SKEY);
+#endif
+#endif
+ /*
+ * Set the I/O buffer to the provided array. We
+ * allocated a buffer large enough for full-duplex
+ * behaviour with all allowed sizes of SSL records,
+ * hence we set the last argument to 1 (which means
+ * "split the buffer into separate input and output
+ * areas").
+ */
+ br_ssl_engine_set_buffer(&sc.eng, iobuf, sizeof iobuf, 1);
+
+ /*
+ * Reset the server context, for a new handshake.
+ */
+ br_ssl_server_reset(&sc);
+
+ /*
+ * Initialise the simplified I/O wrapper context.
+ */
+ br_sslio_init(&ioc, &sc.eng, sock_read, &cfd, sock_write, &cfd);
+
+ /*
+ * Read bytes until two successive LF (or CR+LF) are received.
+ */
+ lcwn = 0;
+ for (;;) {
+ unsigned char x;
+
+ if (br_sslio_read(&ioc, &x, 1) < 0) {
+ goto client_drop;
+ }
+ if (x == 0x0D) {
+ continue;
+ }
+ if (x == 0x0A) {
+ if (lcwn) {
+ break;
+ }
+ lcwn = 1;
+ } else {
+ lcwn = 0;
+ }
+ }
+
+ /*
+ * Write a response and close the connection.
+ */
+ br_sslio_write_all(&ioc, HTTP_RES, strlen(HTTP_RES));
+ br_sslio_close(&ioc);
+
+ client_drop:
+ err = br_ssl_engine_last_error(&sc.eng);
+ if (err == 0) {
+ fprintf(stderr, "SSL closed (correctly).\n");
+ } else {
+ fprintf(stderr, "SSL error: %d\n", err);
+ }
+ close(cfd);
+ }
+}
--- /dev/null
+/*
+ * 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 inner.h */
+void
+br_ccopy(uint32_t ctl, void *dst, const void *src, size_t len)
+{
+ unsigned char *d;
+ const unsigned char *s;
+
+ d = dst;
+ s = src;
+ while (len -- > 0) {
+ uint32_t x, y;
+
+ x = *s ++;
+ y = *d;
+ *d = MUX(ctl, x, y);
+ d ++;
+ }
+}
--- /dev/null
+/*
+ * 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 inner.h */
+void
+br_range_dec16be(uint16_t *v, size_t num, const void *src)
+{
+ const unsigned char *buf;
+
+ buf = src;
+ while (num -- > 0) {
+ *v ++ = br_dec16be(buf);
+ buf += 2;
+ }
+}
--- /dev/null
+/*
+ * 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 inner.h */
+void
+br_range_dec16le(uint16_t *v, size_t num, const void *src)
+{
+ const unsigned char *buf;
+
+ buf = src;
+ while (num -- > 0) {
+ *v ++ = br_dec16le(buf);
+ buf += 2;
+ }
+}
--- /dev/null
+/*
+ * 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 inner.h */
+void
+br_range_dec32be(uint32_t *v, size_t num, const void *src)
+{
+ const unsigned char *buf;
+
+ buf = src;
+ while (num -- > 0) {
+ *v ++ = br_dec32be(buf);
+ buf += 4;
+ }
+}
--- /dev/null
+/*
+ * 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 inner.h */
+void
+br_range_dec32le(uint32_t *v, size_t num, const void *src)
+{
+ const unsigned char *buf;
+
+ buf = src;
+ while (num -- > 0) {
+ *v ++ = br_dec32le(buf);
+ buf += 4;
+ }
+}
--- /dev/null
+/*
+ * 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 inner.h */
+void
+br_range_dec64be(uint64_t *v, size_t num, const void *src)
+{
+ const unsigned char *buf;
+
+ buf = src;
+ while (num -- > 0) {
+ *v ++ = br_dec64be(buf);
+ buf += 8;
+ }
+}
--- /dev/null
+/*
+ * 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 inner.h */
+void
+br_range_dec64le(uint64_t *v, size_t num, const void *src)
+{
+ const unsigned char *buf;
+
+ buf = src;
+ while (num -- > 0) {
+ *v ++ = br_dec64le(buf);
+ buf += 8;
+ }
+}
--- /dev/null
+/*
+ * 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 inner.h */
+void
+br_range_enc16be(void *dst, const uint16_t *v, size_t num)
+{
+ unsigned char *buf;
+
+ buf = dst;
+ while (num -- > 0) {
+ br_enc16be(buf, *v ++);
+ buf += 2;
+ }
+}
--- /dev/null
+/*
+ * 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 inner.h */
+void
+br_range_enc16le(void *dst, const uint16_t *v, size_t num)
+{
+ unsigned char *buf;
+
+ buf = dst;
+ while (num -- > 0) {
+ br_enc16le(buf, *v ++);
+ buf += 2;
+ }
+}
--- /dev/null
+/*
+ * 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 inner.h */
+void
+br_range_enc32be(void *dst, const uint32_t *v, size_t num)
+{
+ unsigned char *buf;
+
+ buf = dst;
+ while (num -- > 0) {
+ br_enc32be(buf, *v ++);
+ buf += 4;
+ }
+}
--- /dev/null
+/*
+ * 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 inner.h */
+void
+br_range_enc32le(void *dst, const uint32_t *v, size_t num)
+{
+ unsigned char *buf;
+
+ buf = dst;
+ while (num -- > 0) {
+ br_enc32le(buf, *v ++);
+ buf += 4;
+ }
+}
--- /dev/null
+/*
+ * 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 inner.h */
+void
+br_range_enc64be(void *dst, const uint64_t *v, size_t num)
+{
+ unsigned char *buf;
+
+ buf = dst;
+ while (num -- > 0) {
+ br_enc64be(buf, *v ++);
+ buf += 8;
+ }
+}
--- /dev/null
+/*
+ * 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 inner.h */
+void
+br_range_enc64le(void *dst, const uint64_t *v, size_t num)
+{
+ unsigned char *buf;
+
+ buf = dst;
+ while (num -- > 0) {
+ br_enc64le(buf, *v ++);
+ buf += 8;
+ }
+}
--- /dev/null
+/* 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 uint8_t t0_datablock[];
+
+
+void br_pem_decoder_init_main(void *t0ctx);
+
+void br_pem_decoder_run(void *t0ctx);
+
+
+
+#include "inner.h"
+
+#define CTX ((br_pem_decoder_context *)((unsigned char *)t0ctx - offsetof(br_pem_decoder_context, cpu)))
+
+/* see bearssl_pem.h */
+void
+br_pem_decoder_init(br_pem_decoder_context *ctx)
+{
+ memset(ctx, 0, sizeof *ctx);
+ ctx->cpu.dp = &ctx->dp_stack[0];
+ ctx->cpu.rp = &ctx->rp_stack[0];
+ br_pem_decoder_init_main(&ctx->cpu);
+ br_pem_decoder_run(&ctx->cpu);
+}
+
+/* see bearssl_pem.h */
+size_t
+br_pem_decoder_push(br_pem_decoder_context *ctx,
+ const void *data, size_t len)
+{
+ if (ctx->event) {
+ return 0;
+ }
+ ctx->hbuf = data;
+ ctx->hlen = len;
+ br_pem_decoder_run(&ctx->cpu);
+ return len - ctx->hlen;
+}
+
+/* see bearssl_pem.h */
+int
+br_pem_decoder_event(br_pem_decoder_context *ctx)
+{
+ int event;
+
+ event = ctx->event;
+ ctx->event = 0;
+ return event;
+}
+
+
+
+static const uint8_t t0_datablock[] = {
+ 0x00, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x42, 0x45, 0x47, 0x49, 0x4E, 0x20,
+ 0x00, 0x2D, 0x2D, 0x2D, 0x2D, 0x45, 0x4E, 0x44, 0x20, 0x00
+};
+
+static const uint8_t t0_codeblock[] = {
+ 0x00, 0x01, 0x00, 0x09, 0x00, 0x00, 0x01, 0x01, 0x07, 0x00, 0x00, 0x01,
+ 0x01, 0x08, 0x00, 0x00, 0x13, 0x13, 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_pem_decoder_context, event)), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_pem_decoder_context, name)), 0x00, 0x00, 0x05,
+ 0x14, 0x2C, 0x14, 0x01, 0x0A, 0x0D, 0x06, 0x03, 0x13, 0x04, 0x76, 0x01,
+ 0x2D, 0x0C, 0x06, 0x05, 0x2E, 0x01, 0x03, 0x2D, 0x00, 0x01, 0x0D, 0x27,
+ 0x05, 0x04, 0x01, 0x03, 0x2D, 0x00, 0x15, 0x2E, 0x01, 0x02, 0x2D, 0x00,
+ 0x01, 0x01, 0x7F, 0x03, 0x00, 0x24, 0x01, 0x00, 0x17, 0x0D, 0x06, 0x03,
+ 0x13, 0x04, 0x3C, 0x01, 0x7F, 0x17, 0x0D, 0x06, 0x13, 0x13, 0x02, 0x00,
+ 0x05, 0x06, 0x2E, 0x01, 0x03, 0x2D, 0x04, 0x03, 0x01, 0x7F, 0x22, 0x01,
+ 0x00, 0x00, 0x04, 0x23, 0x01, 0x01, 0x17, 0x0D, 0x06, 0x09, 0x13, 0x01,
+ 0x00, 0x22, 0x01, 0x00, 0x00, 0x04, 0x14, 0x01, 0x02, 0x17, 0x0D, 0x06,
+ 0x06, 0x13, 0x01, 0x7F, 0x00, 0x04, 0x08, 0x13, 0x01, 0x03, 0x2D, 0x01,
+ 0x00, 0x00, 0x13, 0x01, 0x00, 0x03, 0x00, 0x04, 0xFF, 0x33, 0x01, 0x2C,
+ 0x14, 0x01, 0x2D, 0x0D, 0x06, 0x04, 0x13, 0x01, 0x7F, 0x00, 0x14, 0x31,
+ 0x06, 0x02, 0x13, 0x29, 0x14, 0x01, 0x0A, 0x0D, 0x06, 0x04, 0x13, 0x01,
+ 0x02, 0x00, 0x25, 0x14, 0x1C, 0x06, 0x05, 0x13, 0x2E, 0x01, 0x03, 0x00,
+ 0x03, 0x00, 0x29, 0x14, 0x01, 0x0A, 0x0D, 0x06, 0x04, 0x13, 0x01, 0x03,
+ 0x00, 0x25, 0x14, 0x1C, 0x06, 0x05, 0x13, 0x2E, 0x01, 0x03, 0x00, 0x02,
+ 0x00, 0x01, 0x06, 0x0A, 0x07, 0x03, 0x00, 0x29, 0x14, 0x01, 0x0A, 0x0D,
+ 0x06, 0x04, 0x13, 0x01, 0x03, 0x00, 0x14, 0x01, 0x3D, 0x0D, 0x06, 0x2E,
+ 0x13, 0x29, 0x14, 0x01, 0x0A, 0x0D, 0x06, 0x04, 0x13, 0x01, 0x03, 0x00,
+ 0x2F, 0x05, 0x04, 0x13, 0x01, 0x03, 0x00, 0x01, 0x3D, 0x0C, 0x06, 0x03,
+ 0x01, 0x03, 0x00, 0x02, 0x00, 0x01, 0x0F, 0x10, 0x06, 0x03, 0x01, 0x03,
+ 0x00, 0x02, 0x00, 0x01, 0x04, 0x0F, 0x1B, 0x01, 0x01, 0x00, 0x25, 0x14,
+ 0x1C, 0x06, 0x05, 0x13, 0x2E, 0x01, 0x03, 0x00, 0x02, 0x00, 0x01, 0x06,
+ 0x0A, 0x07, 0x03, 0x00, 0x29, 0x14, 0x01, 0x0A, 0x0D, 0x06, 0x04, 0x13,
+ 0x01, 0x03, 0x00, 0x14, 0x01, 0x3D, 0x0D, 0x06, 0x20, 0x13, 0x2F, 0x05,
+ 0x03, 0x01, 0x03, 0x00, 0x02, 0x00, 0x01, 0x03, 0x10, 0x06, 0x03, 0x01,
+ 0x03, 0x00, 0x02, 0x00, 0x01, 0x0A, 0x0F, 0x1B, 0x02, 0x00, 0x01, 0x02,
+ 0x0F, 0x1B, 0x01, 0x01, 0x00, 0x25, 0x14, 0x1C, 0x06, 0x05, 0x13, 0x2E,
+ 0x01, 0x03, 0x00, 0x02, 0x00, 0x01, 0x06, 0x0A, 0x07, 0x03, 0x00, 0x02,
+ 0x00, 0x01, 0x10, 0x0F, 0x1B, 0x02, 0x00, 0x01, 0x08, 0x0F, 0x1B, 0x02,
+ 0x00, 0x1B, 0x01, 0x00, 0x00, 0x00, 0x14, 0x14, 0x01, 0x80, 0x41, 0x0E,
+ 0x1A, 0x01, 0x80, 0x5A, 0x0B, 0x10, 0x06, 0x05, 0x01, 0x80, 0x41, 0x08,
+ 0x00, 0x14, 0x14, 0x01, 0x80, 0x61, 0x0E, 0x1A, 0x01, 0x80, 0x7A, 0x0B,
+ 0x10, 0x06, 0x05, 0x01, 0x80, 0x47, 0x08, 0x00, 0x14, 0x14, 0x01, 0x30,
+ 0x0E, 0x1A, 0x01, 0x39, 0x0B, 0x10, 0x06, 0x04, 0x01, 0x04, 0x07, 0x00,
+ 0x14, 0x01, 0x2B, 0x0D, 0x06, 0x04, 0x13, 0x01, 0x3E, 0x00, 0x14, 0x01,
+ 0x2F, 0x0D, 0x06, 0x04, 0x13, 0x01, 0x3F, 0x00, 0x01, 0x3D, 0x0C, 0x1E,
+ 0x00, 0x00, 0x28, 0x01, 0x01, 0x2D, 0x23, 0x06, 0x02, 0x04, 0x7B, 0x04,
+ 0x75, 0x00, 0x14, 0x12, 0x2A, 0x14, 0x05, 0x04, 0x1F, 0x01, 0x7F, 0x00,
+ 0x2C, 0x2A, 0x14, 0x01, 0x0A, 0x0D, 0x06, 0x05, 0x13, 0x1F, 0x01, 0x00,
+ 0x00, 0x0D, 0x05, 0x05, 0x13, 0x2E, 0x01, 0x00, 0x00, 0x1D, 0x04, 0x5E,
+ 0x00, 0x01, 0x01, 0x27, 0x06, 0x0B, 0x21, 0x01, 0x80, 0x7F, 0x2B, 0x14,
+ 0x06, 0x02, 0x30, 0x00, 0x13, 0x04, 0x6E, 0x00, 0x2C, 0x14, 0x31, 0x05,
+ 0x01, 0x00, 0x13, 0x04, 0x77, 0x00, 0x14, 0x14, 0x01, 0x80, 0x61, 0x0E,
+ 0x1A, 0x01, 0x80, 0x7A, 0x0B, 0x10, 0x06, 0x03, 0x01, 0x20, 0x08, 0x00,
+ 0x01, 0x14, 0x03, 0x00, 0x1A, 0x17, 0x05, 0x05, 0x1F, 0x2E, 0x01, 0x00,
+ 0x00, 0x2C, 0x14, 0x01, 0x0A, 0x0D, 0x06, 0x06, 0x1F, 0x02, 0x00, 0x1A,
+ 0x08, 0x00, 0x2A, 0x17, 0x19, 0x1D, 0x1A, 0x1E, 0x1A, 0x04, 0x62, 0x00,
+ 0x18, 0x14, 0x1C, 0x05, 0x01, 0x00, 0x13, 0x11, 0x04, 0x76, 0x00, 0x20,
+ 0x19, 0x11, 0x00, 0x00, 0x2C, 0x01, 0x0A, 0x0C, 0x06, 0x02, 0x04, 0x78,
+ 0x00, 0x01, 0x01, 0x7F, 0x03, 0x00, 0x2C, 0x14, 0x01, 0x0A, 0x0C, 0x06,
+ 0x09, 0x31, 0x05, 0x04, 0x01, 0x00, 0x03, 0x00, 0x04, 0x70, 0x13, 0x02,
+ 0x00, 0x00, 0x00, 0x14, 0x06, 0x14, 0x1E, 0x14, 0x21, 0x07, 0x16, 0x01,
+ 0x2D, 0x0C, 0x06, 0x08, 0x21, 0x07, 0x1D, 0x01, 0x00, 0x1A, 0x19, 0x00,
+ 0x04, 0x69, 0x21, 0x19, 0x00, 0x00, 0x14, 0x01, 0x0A, 0x0C, 0x1A, 0x01,
+ 0x20, 0x0B, 0x10, 0x00
+};
+
+static const uint16_t t0_caddr[] = {
+ 0,
+ 5,
+ 10,
+ 15,
+ 19,
+ 24,
+ 29,
+ 67,
+ 149,
+ 384,
+ 464,
+ 476,
+ 511,
+ 530,
+ 540,
+ 559,
+ 594,
+ 605,
+ 610,
+ 620,
+ 645,
+ 672
+};
+
+#define T0_INTERPRETED 28
+
+#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_pem_decoder_init_main, 38)
+
+void
+br_pem_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() break
+
+ dp = ((t0_context *)t0ctx)->dp;
+ rp = ((t0_context *)t0ctx)->rp;
+ ip = ((t0_context *)t0ctx)->ip;
+ for (;;) {
+ uint32_t t0x;
+
+ t0x = t0_parse7E_unsigned(&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: {
+ /* < */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a < b));
+
+ }
+ break;
+ case 10: {
+ /* << */
+
+ int c = (int)T0_POPi();
+ uint32_t x = T0_POP();
+ T0_PUSH(x << c);
+
+ }
+ break;
+ case 11: {
+ /* <= */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a <= b));
+
+ }
+ 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: {
+ /* >> */
+
+ int c = (int)T0_POPi();
+ int32_t x = T0_POPi();
+ T0_PUSHi(x >> c);
+
+ }
+ break;
+ case 16: {
+ /* and */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a & b);
+
+ }
+ break;
+ case 17: {
+ /* co */
+ T0_CO();
+ }
+ break;
+ case 18: {
+ /* data-get8 */
+
+ size_t addr = T0_POP();
+ T0_PUSH(t0_datablock[addr]);
+
+ }
+ break;
+ case 19: {
+ /* drop */
+ (void)T0_POP();
+ }
+ break;
+ case 20: {
+ /* dup */
+ T0_PUSH(T0_PEEK(0));
+ }
+ break;
+ case 21: {
+ /* flush-buf */
+
+ if (CTX->ptr > 0) {
+ CTX->dest(CTX->dest_ctx, CTX->buf, CTX->ptr);
+ CTX->ptr = 0;
+ }
+
+ }
+ break;
+ case 22: {
+ /* get8 */
+
+ size_t addr = T0_POP();
+ T0_PUSH(*((unsigned char *)CTX + addr));
+
+ }
+ break;
+ case 23: {
+ /* over */
+ T0_PUSH(T0_PEEK(1));
+ }
+ break;
+ case 24: {
+ /* read8-native */
+
+ if (CTX->hlen > 0) {
+ T0_PUSH(*CTX->hbuf ++);
+ CTX->hlen --;
+ } else {
+ T0_PUSHi(-1);
+ }
+
+ }
+ break;
+ case 25: {
+ /* set8 */
+
+ size_t addr = T0_POP();
+ unsigned x = T0_POP();
+ *((unsigned char *)CTX + addr) = x;
+
+ }
+ break;
+ case 26: {
+ /* swap */
+ T0_SWAP();
+ }
+ break;
+ case 27: {
+ /* write8 */
+
+ unsigned char x = (unsigned char)T0_POP();
+ CTX->buf[CTX->ptr ++] = x;
+ if (CTX->ptr == sizeof CTX->buf) {
+ if (CTX->dest) {
+ CTX->dest(CTX->dest_ctx, CTX->buf, sizeof CTX->buf);
+ }
+ CTX->ptr = 0;
+ }
+
+ }
+ break;
+ }
+
+ } else {
+ T0_ENTER(ip, rp, t0x);
+ }
+ }
+t0_exit:
+ ((t0_context *)t0ctx)->dp = dp;
+ ((t0_context *)t0ctx)->rp = rp;
+ ((t0_context *)t0ctx)->ip = ip;
+}
--- /dev/null
+\ 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_pem_decoder_context *)((unsigned char *)t0ctx - offsetof(br_pem_decoder_context, cpu)))
+
+/* see bearssl_pem.h */
+void
+br_pem_decoder_init(br_pem_decoder_context *ctx)
+{
+ memset(ctx, 0, sizeof *ctx);
+ ctx->cpu.dp = &ctx->dp_stack[0];
+ ctx->cpu.rp = &ctx->rp_stack[0];
+ br_pem_decoder_init_main(&ctx->cpu);
+ br_pem_decoder_run(&ctx->cpu);
+}
+
+/* see bearssl_pem.h */
+size_t
+br_pem_decoder_push(br_pem_decoder_context *ctx,
+ const void *data, size_t len)
+{
+ if (ctx->event) {
+ return 0;
+ }
+ ctx->hbuf = data;
+ ctx->hlen = len;
+ br_pem_decoder_run(&ctx->cpu);
+ return len - ctx->hlen;
+}
+
+/* see bearssl_pem.h */
+int
+br_pem_decoder_event(br_pem_decoder_context *ctx)
+{
+ int event;
+
+ event = ctx->event;
+ ctx->event = 0;
+ return event;
+}
+
+}
+
+\ Define a word that evaluates to the address of a field within the
+\ decoder context.
+: addr:
+ next-word { field }
+ "addr-" field + 0 1 define-word
+ 0 8191 "offsetof(br_pem_decoder_context, " field + ")" + make-CX
+ postpone literal postpone ; ;
+
+addr: event
+addr: name
+addr: buf
+addr: ptr
+
+\ Set a byte at a specific address (offset within the context).
+cc: set8 ( value addr -- ) {
+ size_t addr = T0_POP();
+ unsigned x = T0_POP();
+ *((unsigned char *)CTX + addr) = x;
+}
+
+\ Get a byte at a specific address (offset within the context).
+cc: get8 ( addr -- value ) {
+ size_t addr = T0_POP();
+ T0_PUSH(*((unsigned char *)CTX + addr));
+}
+
+\ Send an event.
+: send-event ( event -- )
+ addr-event set8 co ;
+
+\ Low-level function to read a single byte. Returned value is the byte
+\ (0 to 255), or -1 if there is no available data.
+cc: read8-native ( -- x ) {
+ if (CTX->hlen > 0) {
+ T0_PUSH(*CTX->hbuf ++);
+ CTX->hlen --;
+ } else {
+ T0_PUSHi(-1);
+ }
+}
+
+\ Read next byte. Block until the next byte is available.
+: read8 ( -- x )
+ begin read8-native dup 0< ifnot ret then drop co again ;
+
+\ Read bytes until next end-of-line.
+: skip-newline ( -- )
+ begin read8 `\n <> while repeat ;
+
+\ Read bytes until next end-of-line; verify that they are all whitespace.
+\ This returns -1 if they were all whitespace, 0 otherwise.
+: skip-newline-ws ( -- bool )
+ -1 { r }
+ begin read8 dup `\n <> while ws? ifnot 0 >r then repeat
+ drop r ;
+
+\ Normalise a byte to uppercase (ASCII only).
+: norm-upper ( x -- x )
+ dup dup `a >= swap `z <= and if 32 - then ;
+
+\ Read bytes and compare with the provided string. On mismatch, the
+\ rest of the line is consumed. Matching is not case sensitive.
+: match-string ( str -- bool )
+ begin
+ dup data-get8 norm-upper dup ifnot 2drop -1 ret then
+ read8 norm-upper dup `\n = if drop 2drop 0 ret then
+ = ifnot drop skip-newline 0 ret then
+ 1+
+ again ;
+
+\ Read bytes into the provided buffer, but no more than the provided
+\ count. Reading stops when end-of-line is reached. Returned value
+\ is the count of bytes written to the buffer, or 0 if the buffer size
+\ was exceeded. All bytes are normalised to uppercase (ASCII only).
+: read-bytes ( addr len -- len )
+ dup { orig-len }
+ swap
+ begin
+ over ifnot 2drop skip-newline 0 ret then
+ read8 dup `\n = if 2drop orig-len swap - ret then
+ norm-upper over set8 1+ swap 1- swap
+ again ;
+
+\ Remove trailing dashes from the name buffer.
+: trim-dashes ( len -- )
+ begin dup while
+ 1-
+ dup addr-name + get8 `- <> if
+ addr-name + 1+ 0 swap set8 ret
+ then
+ repeat
+ addr-name set8 ;
+
+\ Scan input for next "begin" banner.
+: next-banner-begin ( -- )
+ begin
+ "-----BEGIN " match-string if
+ addr-name 127 read-bytes
+ dup if trim-dashes ret then
+ drop
+ then
+ again ;
+
+\ Convert a Base64 character to its numerical value. Returned value is
+\ 0 to 63 for Base64 characters, -1 for '=', and -2 for all other characters.
+: from-base64 ( char -- x )
+ dup dup `A >= swap `Z <= and if 65 - ret then
+ dup dup `a >= swap `z <= and if 71 - ret then
+ dup dup `0 >= swap `9 <= and if 4 + ret then
+ dup `+ = if drop 62 ret then
+ dup `/ = if drop 63 ret then
+ `= <> 1- ;
+
+\ Test whether a character is whitespace (but not a newline).
+: ws? ( x -- bool )
+ dup `\n <> swap 32 <= and ;
+
+\ Read next character, skipping whitespace (except newline).
+: next-nonws ( -- x )
+ begin
+ read8 dup ws? ifnot ret then
+ drop
+ again ;
+
+\ Write one byte in the output buffer.
+cc: write8 ( x -- ) {
+ unsigned char x = (unsigned char)T0_POP();
+ CTX->buf[CTX->ptr ++] = x;
+ if (CTX->ptr == sizeof CTX->buf) {
+ if (CTX->dest) {
+ CTX->dest(CTX->dest_ctx, CTX->buf, sizeof CTX->buf);
+ }
+ CTX->ptr = 0;
+ }
+}
+
+\ Flush the output buffer.
+cc: flush-buf ( -- ) {
+ if (CTX->ptr > 0) {
+ CTX->dest(CTX->dest_ctx, CTX->buf, CTX->ptr);
+ CTX->ptr = 0;
+ }
+}
+
+\ Decode the four next Base64 characters. Returned value is:
+\ 0 quartet processed, three bytes produced.
+\ -1 dash encountered as first character (no leading whitespace).
+\ 1 quartet processed, one or two bytes produced, terminator reached.
+\ 2 end-of-line reached.
+\ 3 error.
+\ For all positive return values, the remaining of the current line has been
+\ consumed.
+: decode-next-quartet ( -- r )
+ \ Process first character. It may be a dash.
+ read8 dup `- = if drop -1 ret then
+ dup ws? if drop next-nonws then
+ dup `\n = if drop 2 ret then
+ from-base64 dup 0< if drop skip-newline 3 ret then
+ { acc }
+
+ \ Second character.
+ next-nonws dup `\n = if drop 3 ret then
+ from-base64 dup 0< if drop skip-newline 3 ret then
+ acc 6 << + >acc
+
+ \ Third character: may be an equal sign.
+ next-nonws dup `\n = if drop 3 ret then
+ dup `= = if
+ \ Fourth character must be an equal sign.
+ drop
+ next-nonws dup `\n = if drop 3 ret then
+ skip-newline-ws ifnot drop 3 ret then
+ `= <> if 3 ret then
+ acc 0x0F and if 3 ret then
+ acc 4 >> write8
+ 1 ret
+ then
+ from-base64 dup 0< if drop skip-newline 3 ret then
+ acc 6 << + >acc
+
+ \ Fourth character: may be an equal sign.
+ next-nonws dup `\n = if drop 3 ret then
+ dup `= = if
+ drop skip-newline-ws ifnot 3 ret then
+ acc 0x03 and if 3 ret then
+ acc 10 >> write8
+ acc 2 >> write8
+ 1 ret
+ then
+ from-base64 dup 0< if drop skip-newline 3 ret then
+ acc 6 << + >acc
+ acc 16 >> write8
+ acc 8 >> write8
+ acc write8
+ 0 ;
+
+\ Check trailer line (possibly, the leading dash has been read). This
+\ sends the appropriate event.
+: check-trailer ( bool -- )
+ ifnot
+ begin read8 dup `\n = while drop repeat
+ `- <> if skip-newline 3 send-event ret then
+ then
+ "----END " match-string ifnot 3 send-event ret then
+ flush-buf
+ skip-newline 2 send-event ;
+
+\ Decode one line worth of characters. Returned value is 0 if the end of the
+\ object is reached, -1 otherwise. The end of object or error event is sent.
+: decode-line ( -- bool )
+ -1 { first }
+ begin
+ decode-next-quartet
+ case
+ 0 of endof
+ -1 of
+ first ifnot
+ skip-newline 3 send-event
+ else
+ -1 check-trailer
+ then
+ 0 ret
+ endof
+ 1 of 0 check-trailer 0 ret endof
+ 2 of -1 ret endof
+
+ \ On decoding error
+ drop 3 send-event 0 ret
+ endcase
+ 0 >first
+ again ;
+
+: main ( -- ! )
+ begin
+ next-banner-begin 1 send-event
+ begin decode-line while repeat
+ again ;
--- /dev/null
+/*
+ * 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.
+ */
+
+#ifndef CONFIG_H__
+#define CONFIG_H__
+
+/*
+ * This file contains compile-time flags that can override the
+ * autodetection performed in relevant files. Each flag is a macro; it
+ * deactivates the feature if defined to 0, activates it if defined to a
+ * non-zero integer (normally 1). If the macro is not defined, then
+ * autodetection applies.
+ */
+
+/*
+ * When BR_64 is enabled, 64-bit integer types are assumed to be
+ * efficient (i.e. the architecture has 64-bit registers and can
+ * do 64-bit operations as fast as 32-bit operations).
+ *
+#define BR_64 1
+ */
+
+/*
+ * When BR_SLOW_MUL is enabled, multiplications are assumed to be
+ * substantially slow with regards to other integer operations, thus
+ * making it worth to make more operations for a given task if it allows
+ * using less multiplications.
+ *
+#define BR_SLOW_MUL 1
+ */
+
+/*
+ * When BR_CT_MUL31 is enabled, multiplications of 31-bit values (used
+ * in the "i31" big integer implementation) use an alternate implementation
+ * which is slower and larger than the normal multiplication, but should
+ * ensure constant-time multiplications even on architectures where the
+ * multiplication opcode takes a variable number of cycles to complete.
+ *
+#define BR_CT_MUL31 1
+ */
+
+/*
+ * When BR_USE_URANDOM is enabled, the SSL engine will use /dev/urandom
+ * to automatically obtain quality randomness for seedings its internal
+ * PRNG.
+ *
+#define BR_USE_URANDOM 1
+ */
+
+/*
+ * When BR_USE_WIN32_RAND is enabled, the SSL engine will use the Win32
+ * (CryptoAPI) functions (CryptAcquireContext(), CryptGenRandom()...) to
+ * automatically obtain quality randomness for seedings its internal PRNG.
+ *
+ * Note: if both BR_USE_URANDOM and BR_USE_WIN32_RAND are defined, the
+ * former takes precedence.
+ *
+#define BR_USE_WIN32_RAND 1
+ */
+
+/*
+ * When BR_USE_UNIX_TIME is enabled, the X.509 validation engine obtains
+ * the current time from the OS by calling time(), and assuming that the
+ * returned value (a 'time_t') is an integer that counts time in seconds
+ * since the Unix Epoch (Jan 1st, 1970, 00:00 UTC).
+ *
+#define BR_USE_UNIX_TIME 1
+ */
+
+/*
+ * When BR_USE_WIN32_TIME is enabled, the X.509 validation engine obtains
+ * the current time from the OS by calling the Win32 function
+ * GetSystemTimeAsFileTime().
+ *
+ * Note: if both BR_USE_UNIX_TIME and BR_USE_WIN32_TIME are defined, the
+ * former takes precedence.
+ *
+#define BR_USE_WIN32_TIME 1
+ */
+
+#endif
--- /dev/null
+/*
+ * 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"
+
+/*
+ * Parameters for supported curves (field modulus, and 'b' equation
+ * parameter; both values use the 'i31' format, and 'b' is in Montgomery
+ * representation).
+ */
+
+static const uint32_t P256_P[] = {
+ 0x00000108,
+ 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x00000007,
+ 0x00000000, 0x00000000, 0x00000040, 0x7FFFFF80,
+ 0x000000FF
+};
+
+static const uint32_t P256_R2[] = {
+ 0x00000108,
+ 0x00014000, 0x00018000, 0x00000000, 0x7FF40000,
+ 0x7FEFFFFF, 0x7FF7FFFF, 0x7FAFFFFF, 0x005FFFFF,
+ 0x00000000
+};
+
+static const uint32_t P256_B[] = {
+ 0x00000108,
+ 0x6FEE1803, 0x6229C4BD, 0x21B139BE, 0x327150AA,
+ 0x3567802E, 0x3F7212ED, 0x012E4355, 0x782DD38D,
+ 0x0000000E
+};
+
+static const uint32_t P384_P[] = {
+ 0x0000018C,
+ 0x7FFFFFFF, 0x00000001, 0x00000000, 0x7FFFFFF8,
+ 0x7FFFFFEF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF,
+ 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF,
+ 0x00000FFF
+};
+
+static const uint32_t P384_R2[] = {
+ 0x0000018C,
+ 0x00000000, 0x00000080, 0x7FFFFE00, 0x000001FF,
+ 0x00000800, 0x00000000, 0x7FFFE000, 0x00001FFF,
+ 0x00008000, 0x00008000, 0x00000000, 0x00000000,
+ 0x00000000
+};
+
+static const uint32_t P384_B[] = {
+ 0x0000018C,
+ 0x6E666840, 0x070D0392, 0x5D810231, 0x7651D50C,
+ 0x17E218D6, 0x1B192002, 0x44EFE441, 0x3A524E2B,
+ 0x2719BA5F, 0x41F02209, 0x36C5643E, 0x5813EFFE,
+ 0x000008A5
+};
+
+static const uint32_t P521_P[] = {
+ 0x00000219,
+ 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF,
+ 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF,
+ 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF,
+ 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF,
+ 0x01FFFFFF
+};
+
+static const uint32_t P521_R2[] = {
+ 0x00000219,
+ 0x00001000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000
+};
+
+static const uint32_t P521_B[] = {
+ 0x00000219,
+ 0x540FC00A, 0x228FEA35, 0x2C34F1EF, 0x67BF107A,
+ 0x46FC1CD5, 0x1605E9DD, 0x6937B165, 0x272A3D8F,
+ 0x42785586, 0x44C8C778, 0x15F3B8B4, 0x64B73366,
+ 0x03BA8B69, 0x0D05B42A, 0x21F929A2, 0x2C31C393,
+ 0x00654FAE
+};
+
+typedef struct {
+ const uint32_t *p;
+ const uint32_t *b;
+ const uint32_t *R2;
+ uint32_t p0i;
+} curve_params;
+
+static inline const curve_params *
+id_to_curve(int curve)
+{
+ static const curve_params pp[] = {
+ { P256_P, P256_B, P256_R2, 0x00000001 },
+ { P384_P, P384_B, P384_R2, 0x00000001 },
+ { P521_P, P521_B, P521_R2, 0x00000001 }
+ };
+
+ return &pp[curve - BR_EC_secp256r1];
+}
+
+#define I31_LEN ((BR_MAX_EC_SIZE + 61) / 31)
+
+/*
+ * Type for a point in Jacobian coordinates:
+ * -- three values, x, y and z, in Montgomery representation
+ * -- affine coordinates are X = x / z^2 and Y = y / z^3
+ * -- for the point at infinity, z = 0
+ */
+typedef struct {
+ uint32_t c[3][I31_LEN];
+} jacobian;
+
+/*
+ * We use a custom interpreter that uses a dozen registers, and
+ * only four operations:
+ * MSET(d, a) copy a into d
+ * MADD(d, a) d = d+a (modular)
+ * MSUB(d, a) d = d-a (modular)
+ * MMUL(d, a, b) d = a*b (Montgomery multiplication)
+ * MINV(d, a, b) invert d modulo p; a and b are used as scratch registers
+ * MTZ(d) clear return value if d = 0
+ * Destination of MMUL (d) must be distinct from operands (a and b).
+ * There is no such constraint for MSUB and MADD.
+ *
+ * Registers include the operand coordinates, and temporaries.
+ */
+#define MSET(d, a) (0x0000 + ((d) << 8) + ((a) << 4))
+#define MADD(d, a) (0x1000 + ((d) << 8) + ((a) << 4))
+#define MSUB(d, a) (0x2000 + ((d) << 8) + ((a) << 4))
+#define MMUL(d, a, b) (0x3000 + ((d) << 8) + ((a) << 4) + (b))
+#define MINV(d, a, b) (0x4000 + ((d) << 8) + ((a) << 4) + (b))
+#define MTZ(d) (0x5000 + ((d) << 8))
+#define ENDCODE 0
+
+/*
+ * Registers for the input operands.
+ */
+#define P1x 0
+#define P1y 1
+#define P1z 2
+#define P2x 3
+#define P2y 4
+#define P2z 5
+
+/*
+ * Alternate names for the first input operand.
+ */
+#define Px 0
+#define Py 1
+#define Pz 2
+
+/*
+ * Temporaries.
+ */
+#define t1 6
+#define t2 7
+#define t3 8
+#define t4 9
+#define t5 10
+#define t6 11
+#define t7 12
+
+/*
+ * Extra scratch registers available when there is no second operand (e.g.
+ * for "double" and "affine").
+ */
+#define t8 3
+#define t9 4
+#define t10 5
+
+/*
+ * Doubling formulas are:
+ *
+ * s = 4*x*y^2
+ * m = 3*(x + z^2)*(x - z^2)
+ * x' = m^2 - 2*s
+ * y' = m*(s - x') - 8*y^4
+ * z' = 2*y*z
+ *
+ * If y = 0 (P has order 2) then this yields infinity (z' = 0), as it
+ * should. This case should not happen anyway, because our curves have
+ * prime order, and thus do not contain any point of order 2.
+ *
+ * If P is infinity (z = 0), then again the formulas yield infinity,
+ * which is correct. Thus, this code works for all points.
+ *
+ * Cost: 8 multiplications
+ */
+static const uint16_t code_double[] = {
+ /*
+ * Compute z^2 (in t1).
+ */
+ MMUL(t1, Pz, Pz),
+
+ /*
+ * Compute x-z^2 (in t2) and then x+z^2 (in t1).
+ */
+ MSET(t2, Px),
+ MSUB(t2, t1),
+ MADD(t1, Px),
+
+ /*
+ * Compute m = 3*(x+z^2)*(x-z^2) (in t1).
+ */
+ MMUL(t3, t1, t2),
+ MSET(t1, t3),
+ MADD(t1, t3),
+ MADD(t1, t3),
+
+ /*
+ * Compute s = 4*x*y^2 (in t2) and 2*y^2 (in t3).
+ */
+ MMUL(t3, Py, Py),
+ MADD(t3, t3),
+ MMUL(t2, Px, t3),
+ MADD(t2, t2),
+
+ /*
+ * Compute x' = m^2 - 2*s.
+ */
+ MMUL(Px, t1, t1),
+ MSUB(Px, t2),
+ MSUB(Px, t2),
+
+ /*
+ * Compute z' = 2*y*z.
+ */
+ MMUL(t4, Py, Pz),
+ MSET(Pz, t4),
+ MADD(Pz, t4),
+
+ /*
+ * Compute y' = m*(s - x') - 8*y^4. Note that we already have
+ * 2*y^2 in t3.
+ */
+ MSUB(t2, Px),
+ MMUL(Py, t1, t2),
+ MMUL(t4, t3, t3),
+ MSUB(Py, t4),
+ MSUB(Py, t4),
+
+ ENDCODE
+};
+
+/*
+ * Addtions formulas are:
+ *
+ * u1 = x1 * z2^2
+ * u2 = x2 * z1^2
+ * s1 = y1 * z2^3
+ * s2 = y2 * z1^3
+ * h = u2 - u1
+ * r = s2 - s1
+ * x3 = r^2 - h^3 - 2 * u1 * h^2
+ * y3 = r * (u1 * h^2 - x3) - s1 * h^3
+ * z3 = h * z1 * z2
+ *
+ * If both P1 and P2 are infinity, then z1 == 0 and z2 == 0, implying that
+ * z3 == 0, so the result is correct.
+ * If either of P1 or P2 is infinity, but not both, then z3 == 0, which is
+ * not correct.
+ * h == 0 only if u1 == u2; this happens in two cases:
+ * -- if s1 == s2 then P1 and/or P2 is infinity, or P1 == P2
+ * -- if s1 != s2 then P1 + P2 == infinity (but neither P1 or P2 is infinity)
+ *
+ * Thus, the following situations are not handled correctly:
+ * -- P1 = 0 and P2 != 0
+ * -- P1 != 0 and P2 = 0
+ * -- P1 = P2
+ * All other cases are properly computed. However, even in "incorrect"
+ * situations, the three coordinates still are properly formed field
+ * elements.
+ *
+ * The returned flag is cleared if r == 0. This happens in the following
+ * cases:
+ * -- Both points are on the same horizontal line (same Y coordinate).
+ * -- Both points are infinity.
+ * -- One point is infinity and the other is on line Y = 0.
+ * The third case cannot happen with our curves (there is no valid point
+ * on line Y = 0 since that would be a point of order 2). If the two
+ * source points are non-infinity, then remains only the case where the
+ * two points are on the same horizontal line.
+ *
+ * This allows us to detect the "P1 == P2" case, assuming that P1 != 0 and
+ * P2 != 0:
+ * -- If the returned value is not the point at infinity, then it was properly
+ * computed.
+ * -- Otherwise, if the returned flag is 1, then P1+P2 = 0, and the result
+ * is indeed the point at infinity.
+ * -- Otherwise (result is infinity, flag is 0), then P1 = P2 and we should
+ * use the 'double' code.
+ *
+ * Cost: 16 multiplications
+ */
+static const uint16_t code_add[] = {
+ /*
+ * Compute u1 = x1*z2^2 (in t1) and s1 = y1*z2^3 (in t3).
+ */
+ MMUL(t3, P2z, P2z),
+ MMUL(t1, P1x, t3),
+ MMUL(t4, P2z, t3),
+ MMUL(t3, P1y, t4),
+
+ /*
+ * Compute u2 = x2*z1^2 (in t2) and s2 = y2*z1^3 (in t4).
+ */
+ MMUL(t4, P1z, P1z),
+ MMUL(t2, P2x, t4),
+ MMUL(t5, P1z, t4),
+ MMUL(t4, P2y, t5),
+
+ /*
+ * Compute h = u2 - u1 (in t2) and r = s2 - s1 (in t4).
+ */
+ MSUB(t2, t1),
+ MSUB(t4, t3),
+
+ /*
+ * Report cases where r = 0 through the returned flag.
+ */
+ MTZ(t4),
+
+ /*
+ * Compute u1*h^2 (in t6) and h^3 (in t5).
+ */
+ MMUL(t7, t2, t2),
+ MMUL(t6, t1, t7),
+ MMUL(t5, t7, t2),
+
+ /*
+ * Compute x3 = r^2 - h^3 - 2*u1*h^2.
+ * t1 and t7 can be used as scratch registers.
+ */
+ MMUL(P1x, t4, t4),
+ MSUB(P1x, t5),
+ MSUB(P1x, t6),
+ MSUB(P1x, t6),
+
+ /*
+ * Compute y3 = r*(u1*h^2 - x3) - s1*h^3.
+ */
+ MSUB(t6, P1x),
+ MMUL(P1y, t4, t6),
+ MMUL(t1, t5, t3),
+ MSUB(P1y, t1),
+
+ /*
+ * Compute z3 = h*z1*z2.
+ */
+ MMUL(t1, P1z, P2z),
+ MMUL(P1z, t1, t2),
+
+ ENDCODE
+};
+
+/*
+ * Check that the point is on the curve. This code snippet assumes the
+ * following conventions:
+ * -- Coordinates x and y have been freshly decoded in P1 (but not
+ * converted to Montgomery coordinates yet).
+ * -- P2x, P2y and P2z are set to, respectively, R^2, b*R and 1.
+ */
+static const uint16_t code_check[] = {
+
+ /* Convert x and y to Montgomery representation. */
+ MMUL(t1, P1x, P2x),
+ MMUL(t2, P1y, P2x),
+ MSET(P1x, t1),
+ MSET(P1y, t2),
+
+ /* Compute x^3 in t1. */
+ MMUL(t2, P1x, P1x),
+ MMUL(t1, P1x, t2),
+
+ /* Subtract 3*x from t1. */
+ MSUB(t1, P1x),
+ MSUB(t1, P1x),
+ MSUB(t1, P1x),
+
+ /* Add b. */
+ MADD(t1, P2y),
+
+ /* Compute y^2 in t2. */
+ MMUL(t2, P1y, P1y),
+
+ /* Compare y^2 with x^3 - 3*x + b; they must match. */
+ MSUB(t1, t2),
+ MTZ(t1),
+
+ /* Set z to 1 (in Montgomery representation). */
+ MMUL(P1z, P2x, P2z),
+
+ ENDCODE
+};
+
+/*
+ * Conversion back to affine coordinates. This code snippet assumes that
+ * the z coordinate of P2 is set to 1 (not in Montgomery representation).
+ */
+static const uint16_t code_affine[] = {
+
+ /* Save z*R in t1. */
+ MSET(t1, P1z),
+
+ /* Compute z^3 in t2. */
+ MMUL(t2, P1z, P1z),
+ MMUL(t3, P1z, t2),
+ MMUL(t2, t3, P2z),
+
+ /* Invert to (1/z^3) in t2. */
+ MINV(t2, t3, t4),
+
+ /* Compute y. */
+ MSET(t3, P1y),
+ MMUL(P1y, t2, t3),
+
+ /* Compute (1/z^2) in t3. */
+ MMUL(t3, t2, t1),
+
+ /* Compute x. */
+ MSET(t2, P1x),
+ MMUL(P1x, t2, t3),
+
+ ENDCODE
+};
+
+static uint32_t
+run_code(jacobian *P1, const jacobian *P2,
+ const curve_params *cc, const uint16_t *code)
+{
+ uint32_t r;
+ uint32_t t[13][I31_LEN];
+ size_t u;
+
+ r = 1;
+
+ /*
+ * Copy the two operands in the dedicated registers.
+ */
+ memcpy(t[P1x], P1->c, 3 * I31_LEN * sizeof(uint32_t));
+ memcpy(t[P2x], P2->c, 3 * I31_LEN * sizeof(uint32_t));
+
+ /*
+ * Run formulas.
+ */
+ for (u = 0;; u ++) {
+ unsigned op, d, a, b;
+
+ op = code[u];
+ if (op == 0) {
+ break;
+ }
+ d = (op >> 8) & 0x0F;
+ a = (op >> 4) & 0x0F;
+ b = op & 0x0F;
+ op >>= 12;
+ switch (op) {
+ uint32_t ctl;
+ size_t plen;
+ unsigned char tp[(BR_MAX_EC_SIZE + 7) >> 3];
+
+ case 0:
+ memcpy(t[d], t[a], I31_LEN * sizeof(uint32_t));
+ break;
+ case 1:
+ ctl = br_i31_add(t[d], t[a], 1);
+ ctl |= NOT(br_i31_sub(t[d], cc->p, 0));
+ br_i31_sub(t[d], cc->p, ctl);
+ break;
+ case 2:
+ br_i31_add(t[d], cc->p, br_i31_sub(t[d], t[a], 1));
+ break;
+ case 3:
+ br_i31_montymul(t[d], t[a], t[b], cc->p, cc->p0i);
+ break;
+ case 4:
+ plen = (cc->p[0] - (cc->p[0] >> 5) + 7) >> 3;
+ br_i31_encode(tp, plen, cc->p);
+ tp[plen - 1] -= 2;
+ br_i31_modpow(t[d], tp, plen,
+ cc->p, cc->p0i, t[a], t[b]);
+ break;
+ default:
+ r &= ~br_i31_iszero(t[d]);
+ break;
+ }
+ }
+
+ /*
+ * Copy back result.
+ */
+ memcpy(P1->c, t[P1x], 3 * I31_LEN * sizeof(uint32_t));
+ return r;
+}
+
+static void
+set_one(uint32_t *x, const uint32_t *p)
+{
+ size_t plen;
+
+ plen = (p[0] + 63) >> 5;
+ memset(x, 0, plen * sizeof *x);
+ x[0] = p[0];
+ x[1] = 0x00000001;
+}
+
+static void
+point_zero(jacobian *P, const curve_params *cc)
+{
+ memset(P, 0, sizeof *P);
+ P->c[0][0] = P->c[1][0] = P->c[2][0] = cc->p[0];
+}
+
+static inline void
+point_double(jacobian *P, const curve_params *cc)
+{
+ run_code(P, P, cc, code_double);
+}
+
+static inline uint32_t
+point_add(jacobian *P1, const jacobian *P2, const curve_params *cc)
+{
+ return run_code(P1, P2, cc, code_add);
+}
+
+static void
+point_mul(jacobian *P, const unsigned char *x, size_t xlen,
+ const curve_params *cc)
+{
+ /*
+ * We do a simple double-and-add ladder with a 2-bit window
+ * to make only one add every two doublings. We thus first
+ * precompute 2P and 3P in some local buffers.
+ *
+ * We always perform two doublings and one addition; the
+ * addition is with P, 2P and 3P and is done in a temporary
+ * array.
+ *
+ * The addition code cannot handle cases where one of the
+ * operands is infinity, which is the case at the start of the
+ * ladder. We therefore need to maintain a flag that controls
+ * this situation.
+ */
+ uint32_t qz;
+ jacobian P2, P3, Q, T, U;
+
+ memcpy(&P2, P, sizeof P2);
+ point_double(&P2, cc);
+ memcpy(&P3, P, sizeof P3);
+ point_add(&P3, &P2, cc);
+
+ point_zero(&Q, cc);
+ qz = 1;
+ while (xlen -- > 0) {
+ int k;
+
+ for (k = 6; k >= 0; k -= 2) {
+ uint32_t bits;
+ uint32_t bnz;
+
+ point_double(&Q, cc);
+ point_double(&Q, cc);
+ memcpy(&T, P, sizeof T);
+ memcpy(&U, &Q, sizeof U);
+ bits = (*x >> k) & (uint32_t)3;
+ bnz = NEQ(bits, 0);
+ CCOPY(EQ(bits, 2), &T, &P2, sizeof T);
+ CCOPY(EQ(bits, 3), &T, &P3, sizeof T);
+ point_add(&U, &T, cc);
+ CCOPY(bnz & qz, &Q, &T, sizeof Q);
+ CCOPY(bnz & ~qz, &Q, &U, sizeof Q);
+ qz &= ~bnz;
+ }
+ x ++;
+ }
+ memcpy(P, &Q, sizeof Q);
+}
+
+/*
+ * Decode point into Jacobian coordinates. This function does not support
+ * the point at infinity. If the point is invalid then this returns 0, but
+ * the coordinates are still set to properly formed field elements.
+ */
+static uint32_t
+point_decode(jacobian *P, const void *src, size_t len, const curve_params *cc)
+{
+ /*
+ * Points must use uncompressed format:
+ * -- first byte is 0x04;
+ * -- coordinates X and Y use unsigned big-endian, with the same
+ * length as the field modulus.
+ *
+ * We don't support hybrid format (uncompressed, but first byte
+ * has value 0x06 or 0x07, depending on the least significant bit
+ * of Y) because it is rather useless, and explicitly forbidden
+ * by PKIX (RFC 5480, section 2.2).
+ *
+ * We don't support compressed format either, because it is not
+ * much used in practice (there are or were patent-related
+ * concerns about point compression, which explains the lack of
+ * generalised support). Also, point compression support would
+ * need a bit more code.
+ */
+ const unsigned char *buf;
+ size_t plen, zlen;
+ uint32_t r;
+ jacobian Q;
+
+ buf = src;
+ point_zero(P, cc);
+ plen = (cc->p[0] - (cc->p[0] >> 5) + 7) >> 3;
+ if (len != 1 + (plen << 1)) {
+ return 0;
+ }
+ r = br_i31_decode_mod(P->c[0], buf + 1, plen, cc->p);
+ r &= br_i31_decode_mod(P->c[1], buf + 1 + plen, plen, cc->p);
+
+ /*
+ * Check first byte.
+ */
+ r &= EQ(buf[0], 0x04);
+ /* obsolete
+ r &= EQ(buf[0], 0x04) | (EQ(buf[0] & 0xFE, 0x06)
+ & ~(uint32_t)(buf[0] ^ buf[plen << 1]));
+ */
+
+ /*
+ * Convert coordinates and check that the point is valid.
+ */
+ zlen = ((cc->p[0] + 63) >> 5) * sizeof(uint32_t);
+ memcpy(Q.c[0], cc->R2, zlen);
+ memcpy(Q.c[1], cc->b, zlen);
+ set_one(Q.c[2], cc->p);
+ r &= ~run_code(P, &Q, cc, code_check);
+ return r;
+}
+
+/*
+ * Encode a point. This method assumes that the point is correct and is
+ * not the point at infinity. Encoded size is always 1+2*plen, where
+ * plen is the field modulus length, in bytes.
+ */
+static void
+point_encode(void *dst, const jacobian *P, const curve_params *cc)
+{
+ unsigned char *buf;
+ uint32_t xbl;
+ size_t plen;
+ jacobian Q, T;
+
+ buf = dst;
+ xbl = cc->p[0];
+ xbl -= (xbl >> 5);
+ plen = (xbl + 7) >> 3;
+ buf[0] = 0x04;
+ memcpy(&Q, P, sizeof *P);
+ set_one(T.c[2], cc->p);
+ run_code(&Q, &T, cc, code_affine);
+ br_i31_encode(buf + 1, plen, Q.c[0]);
+ br_i31_encode(buf + 1 + plen, plen, Q.c[1]);
+}
+
+static const br_ec_curve_def *
+id_to_curve_def(int curve)
+{
+ switch (curve) {
+ case BR_EC_secp256r1:
+ return &br_secp256r1;
+ case BR_EC_secp384r1:
+ return &br_secp384r1;
+ case BR_EC_secp521r1:
+ return &br_secp521r1;
+ }
+ return NULL;
+}
+
+static const unsigned char *
+api_generator(int curve, size_t *len)
+{
+ const br_ec_curve_def *cd;
+
+ cd = id_to_curve_def(curve);
+ *len = cd->generator_len;
+ return cd->generator;
+}
+
+static const unsigned char *
+api_order(int curve, size_t *len)
+{
+ const br_ec_curve_def *cd;
+
+ cd = id_to_curve_def(curve);
+ *len = cd->order_len;
+ return cd->order;
+}
+
+static uint32_t
+api_mul(unsigned char *G, size_t Glen,
+ const unsigned char *x, size_t xlen, int curve)
+{
+ uint32_t r;
+ const curve_params *cc;
+ jacobian P;
+
+ cc = id_to_curve(curve);
+ r = point_decode(&P, G, Glen, cc);
+ point_mul(&P, x, xlen, cc);
+ point_encode(G, &P, cc);
+ return r;
+}
+
+static uint32_t
+api_muladd(unsigned char *A, const unsigned char *B, size_t len,
+ const unsigned char *x, size_t xlen,
+ const unsigned char *y, size_t ylen, int curve)
+{
+ uint32_t r, t, z;
+ const curve_params *cc;
+ jacobian P, Q;
+
+ /*
+ * TODO: see about merging the two ladders. Right now, we do
+ * two independant point multiplications, which is a bit
+ * wasteful of CPU resources (but yields short code).
+ */
+
+ cc = id_to_curve(curve);
+ r = point_decode(&P, A, len, cc);
+ r &= point_decode(&Q, B, len, cc);
+ point_mul(&P, x, xlen, cc);
+ point_mul(&Q, y, ylen, cc);
+
+ /*
+ * We want to compute P+Q. Since the base points A and B are distinct
+ * from infinity, and the multipliers are non-zero and lower than the
+ * curve order, then we know that P and Q are non-infinity. This
+ * leaves two special situations to test for:
+ * -- If P = Q then we must use point_double().
+ * -- If P+Q = 0 then we must report an error.
+ */
+ t = point_add(&P, &Q, cc);
+ point_double(&Q, cc);
+ z = br_i31_iszero(P.c[2]);
+
+ /*
+ * If z is 1 then either P+Q = 0 (t = 1) or P = Q (t = 0). So we
+ * have the following:
+ *
+ * z = 0, t = 0 return P (normal addition)
+ * z = 0, t = 1 return P (normal addition)
+ * z = 1, t = 0 return Q (a 'double' case)
+ * z = 1, t = 1 report an error (P+Q = 0)
+ */
+ CCOPY(z & ~t, &P, &Q, sizeof Q);
+ point_encode(A, &P, cc);
+ r &= ~(z & t);
+
+ return r;
+}
+
+/* see bearssl_ec.h */
+const br_ec_impl br_ec_prime_i31 = {
+ (uint32_t)0x03800000,
+ &api_generator,
+ &api_order,
+ &api_mul,
+ &api_muladd
+};
--- /dev/null
+/*
+ * 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"
+
+static const uint32_t P256_P[] = {
+ 0x00000108,
+ 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x00000007,
+ 0x00000000, 0x00000000, 0x00000040, 0x7FFFFF80,
+ 0x000000FF
+};
+
+static const uint32_t P256_B[] = {
+ 0x00000108,
+ 0x6FEE1803, 0x6229C4BD, 0x21B139BE, 0x327150AA,
+ 0x3567802E, 0x3F7212ED, 0x012E4355, 0x782DD38D,
+ 0x0000000E
+};
+
+/* see inner.h */
+const br_ec_prime_i31_curve br_ec_prime_i31_secp256r1 = {
+ P256_P,
+ P256_B,
+ 0x00000001
+};
--- /dev/null
+/*
+ * 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"
+
+static const uint32_t P384_P[] = {
+ 0x0000018C,
+ 0x7FFFFFFF, 0x00000001, 0x00000000, 0x7FFFFFF8,
+ 0x7FFFFFEF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF,
+ 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF,
+ 0x00000FFF
+};
+
+static const uint32_t P384_B[] = {
+ 0x0000018C,
+ 0x6E666840, 0x070D0392, 0x5D810231, 0x7651D50C,
+ 0x17E218D6, 0x1B192002, 0x44EFE441, 0x3A524E2B,
+ 0x2719BA5F, 0x41F02209, 0x36C5643E, 0x5813EFFE,
+ 0x000008A5
+};
+
+/* see inner.h */
+const br_ec_prime_i31_curve br_ec_prime_i31_secp384r1 = {
+ P384_P,
+ P384_B,
+ 0x00000001
+};
--- /dev/null
+/*
+ * 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"
+
+static const uint32_t P521_P[] = {
+ 0x00000219,
+ 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF,
+ 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF,
+ 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF,
+ 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF,
+ 0x01FFFFFF
+};
+
+static const uint32_t P521_B[] = {
+ 0x00000219,
+ 0x540FC00A, 0x228FEA35, 0x2C34F1EF, 0x67BF107A,
+ 0x46FC1CD5, 0x1605E9DD, 0x6937B165, 0x272A3D8F,
+ 0x42785586, 0x44C8C778, 0x15F3B8B4, 0x64B73366,
+ 0x03BA8B69, 0x0D05B42A, 0x21F929A2, 0x2C31C393,
+ 0x00654FAE
+};
+
+/* see inner.h */
+const br_ec_prime_i31_curve br_ec_prime_i31_secp521r1 = {
+ P521_P,
+ P521_B,
+ 0x00000001
+};
--- /dev/null
+/*
+ * 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"
+
+static const unsigned char P256_N[] = {
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xBC, 0xE6, 0xFA, 0xAD, 0xA7, 0x17, 0x9E, 0x84,
+ 0xF3, 0xB9, 0xCA, 0xC2, 0xFC, 0x63, 0x25, 0x51
+};
+
+static const unsigned char P256_G[] = {
+ 0x04, 0x6B, 0x17, 0xD1, 0xF2, 0xE1, 0x2C, 0x42,
+ 0x47, 0xF8, 0xBC, 0xE6, 0xE5, 0x63, 0xA4, 0x40,
+ 0xF2, 0x77, 0x03, 0x7D, 0x81, 0x2D, 0xEB, 0x33,
+ 0xA0, 0xF4, 0xA1, 0x39, 0x45, 0xD8, 0x98, 0xC2,
+ 0x96, 0x4F, 0xE3, 0x42, 0xE2, 0xFE, 0x1A, 0x7F,
+ 0x9B, 0x8E, 0xE7, 0xEB, 0x4A, 0x7C, 0x0F, 0x9E,
+ 0x16, 0x2B, 0xCE, 0x33, 0x57, 0x6B, 0x31, 0x5E,
+ 0xCE, 0xCB, 0xB6, 0x40, 0x68, 0x37, 0xBF, 0x51,
+ 0xF5
+};
+
+/* see inner.h */
+const br_ec_curve_def br_secp256r1 = {
+ BR_EC_secp256r1,
+ P256_N, sizeof P256_N,
+ P256_G, sizeof P256_G
+};
--- /dev/null
+/*
+ * 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"
+
+static const unsigned char P384_N[] = {
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xC7, 0x63, 0x4D, 0x81, 0xF4, 0x37, 0x2D, 0xDF,
+ 0x58, 0x1A, 0x0D, 0xB2, 0x48, 0xB0, 0xA7, 0x7A,
+ 0xEC, 0xEC, 0x19, 0x6A, 0xCC, 0xC5, 0x29, 0x73
+};
+
+static const unsigned char P384_G[] = {
+ 0x04, 0xAA, 0x87, 0xCA, 0x22, 0xBE, 0x8B, 0x05,
+ 0x37, 0x8E, 0xB1, 0xC7, 0x1E, 0xF3, 0x20, 0xAD,
+ 0x74, 0x6E, 0x1D, 0x3B, 0x62, 0x8B, 0xA7, 0x9B,
+ 0x98, 0x59, 0xF7, 0x41, 0xE0, 0x82, 0x54, 0x2A,
+ 0x38, 0x55, 0x02, 0xF2, 0x5D, 0xBF, 0x55, 0x29,
+ 0x6C, 0x3A, 0x54, 0x5E, 0x38, 0x72, 0x76, 0x0A,
+ 0xB7, 0x36, 0x17, 0xDE, 0x4A, 0x96, 0x26, 0x2C,
+ 0x6F, 0x5D, 0x9E, 0x98, 0xBF, 0x92, 0x92, 0xDC,
+ 0x29, 0xF8, 0xF4, 0x1D, 0xBD, 0x28, 0x9A, 0x14,
+ 0x7C, 0xE9, 0xDA, 0x31, 0x13, 0xB5, 0xF0, 0xB8,
+ 0xC0, 0x0A, 0x60, 0xB1, 0xCE, 0x1D, 0x7E, 0x81,
+ 0x9D, 0x7A, 0x43, 0x1D, 0x7C, 0x90, 0xEA, 0x0E,
+ 0x5F
+};
+
+/* see inner.h */
+const br_ec_curve_def br_secp384r1 = {
+ BR_EC_secp384r1,
+ P384_N, sizeof P384_N,
+ P384_G, sizeof P384_G
+};
--- /dev/null
+/*
+ * 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"
+
+static const unsigned char P521_N[] = {
+ 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFA, 0x51, 0x86, 0x87, 0x83, 0xBF, 0x2F,
+ 0x96, 0x6B, 0x7F, 0xCC, 0x01, 0x48, 0xF7, 0x09,
+ 0xA5, 0xD0, 0x3B, 0xB5, 0xC9, 0xB8, 0x89, 0x9C,
+ 0x47, 0xAE, 0xBB, 0x6F, 0xB7, 0x1E, 0x91, 0x38,
+ 0x64, 0x09
+};
+
+static const unsigned char P521_G[] = {
+ 0x04, 0x00, 0xC6, 0x85, 0x8E, 0x06, 0xB7, 0x04,
+ 0x04, 0xE9, 0xCD, 0x9E, 0x3E, 0xCB, 0x66, 0x23,
+ 0x95, 0xB4, 0x42, 0x9C, 0x64, 0x81, 0x39, 0x05,
+ 0x3F, 0xB5, 0x21, 0xF8, 0x28, 0xAF, 0x60, 0x6B,
+ 0x4D, 0x3D, 0xBA, 0xA1, 0x4B, 0x5E, 0x77, 0xEF,
+ 0xE7, 0x59, 0x28, 0xFE, 0x1D, 0xC1, 0x27, 0xA2,
+ 0xFF, 0xA8, 0xDE, 0x33, 0x48, 0xB3, 0xC1, 0x85,
+ 0x6A, 0x42, 0x9B, 0xF9, 0x7E, 0x7E, 0x31, 0xC2,
+ 0xE5, 0xBD, 0x66, 0x01, 0x18, 0x39, 0x29, 0x6A,
+ 0x78, 0x9A, 0x3B, 0xC0, 0x04, 0x5C, 0x8A, 0x5F,
+ 0xB4, 0x2C, 0x7D, 0x1B, 0xD9, 0x98, 0xF5, 0x44,
+ 0x49, 0x57, 0x9B, 0x44, 0x68, 0x17, 0xAF, 0xBD,
+ 0x17, 0x27, 0x3E, 0x66, 0x2C, 0x97, 0xEE, 0x72,
+ 0x99, 0x5E, 0xF4, 0x26, 0x40, 0xC5, 0x50, 0xB9,
+ 0x01, 0x3F, 0xAD, 0x07, 0x61, 0x35, 0x3C, 0x70,
+ 0x86, 0xA2, 0x72, 0xC2, 0x40, 0x88, 0xBE, 0x94,
+ 0x76, 0x9F, 0xD1, 0x66, 0x50
+};
+
+/* see inner.h */
+const br_ec_curve_def br_secp521r1 = {
+ BR_EC_secp521r1,
+ P521_N, sizeof P521_N,
+ P521_G, sizeof P521_G
+};
--- /dev/null
+/*
+ * 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_ec.h */
+size_t
+br_ecdsa_asn1_to_raw(void *sig, size_t sig_len)
+{
+ /*
+ * Note: this code is a bit lenient in that it accepts a few
+ * deviations to DER with regards to minimality of encoding of
+ * lengths and integer values. These deviations are still
+ * unambiguous.
+ */
+
+ unsigned char *buf, *r, *s;
+ size_t zlen, rlen, slen, off;
+ unsigned char tmp[254];
+
+ buf = sig;
+ if (sig_len < 8) {
+ return 0;
+ }
+ if (buf[0] != 0x30) {
+ return 0;
+ }
+ zlen = buf[1];
+ if (zlen > 0x80) {
+ if (zlen != 0x81) {
+ return 0;
+ }
+ zlen = buf[2];
+ if (zlen != sig_len - 3) {
+ return 0;
+ }
+ off = 3;
+ } else {
+ if (zlen != sig_len - 2) {
+ return 0;
+ }
+ off = 2;
+ }
+ if (buf[off ++] != 0x02) {
+ return 0;
+ }
+ rlen = buf[off ++];
+ if (rlen >= 0x80) {
+ return 0;
+ }
+ r = buf + off;
+ off += rlen;
+ if (off + 2 > sig_len) {
+ return 0;
+ }
+ if (buf[off ++] != 0x02) {
+ return 0;
+ }
+ slen = buf[off ++];
+ if (slen >= 0x80 || slen != sig_len - off) {
+ return 0;
+ }
+ s = buf + off;
+
+ while (rlen > 0 && *r == 0) {
+ rlen --;
+ r ++;
+ }
+ while (slen > 0 && *s == 0) {
+ slen --;
+ s ++;
+ }
+
+ zlen = rlen > slen ? rlen : slen;
+ sig_len = zlen << 1;
+ memset(tmp, 0, sig_len);
+ memcpy(tmp + zlen - rlen, r, rlen);
+ memcpy(tmp + sig_len - slen, s, slen);
+ memcpy(sig, tmp, sig_len);
+ return sig_len;
+}
--- /dev/null
+/*
+ * 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 inner.h */
+void
+br_ecdsa_i31_bits2int(uint32_t *x,
+ const void *src, size_t len, uint32_t ebitlen)
+{
+ uint32_t bitlen, hbitlen;
+ int sc;
+
+ bitlen = ebitlen - (ebitlen >> 5);
+ hbitlen = (uint32_t)len << 3;
+ if (hbitlen > bitlen) {
+ len = (bitlen + 7) >> 3;
+ sc = (int)((hbitlen - bitlen) & 7);
+ } else {
+ sc = 0;
+ }
+ br_i31_zero(x, ebitlen);
+ br_i31_decode(x, src, len);
+ br_i31_rshift(x, sc);
+ x[0] = ebitlen;
+}
--- /dev/null
+/*
+ * 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"
+
+#define ORDER_LEN ((BR_MAX_EC_SIZE + 7) >> 3)
+
+/* see bearssl_ec.h */
+size_t
+br_ecdsa_i31_sign_asn1(const br_ec_impl *impl,
+ const br_hash_class *hf, const void *hash_value,
+ const br_ec_private_key *sk, void *sig)
+{
+ unsigned char rsig[(ORDER_LEN << 1) + 12];
+ size_t sig_len;
+
+ sig_len = br_ecdsa_i31_sign_raw(impl, hf, hash_value, sk, rsig);
+ if (sig_len == 0) {
+ return 0;
+ }
+ sig_len = br_ecdsa_raw_to_asn1(rsig, sig_len);
+ memcpy(sig, rsig, sig_len);
+ return sig_len;
+}
--- /dev/null
+/*
+ * 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"
+
+#define I31_LEN ((BR_MAX_EC_SIZE + 61) / 31)
+#define POINT_LEN (1 + (((BR_MAX_EC_SIZE + 7) >> 3) << 1))
+#define ORDER_LEN ((BR_MAX_EC_SIZE + 7) >> 3)
+
+/* see bearssl_ec.h */
+size_t
+br_ecdsa_i31_sign_raw(const br_ec_impl *impl,
+ const br_hash_class *hf, const void *hash_value,
+ const br_ec_private_key *sk, void *sig)
+{
+ /*
+ * IMPORTANT: this code is fit only for curves with a prime
+ * order. This is needed so that modular reduction of the X
+ * coordinate of a point can be done with a simple subtraction.
+ * We also rely on the last byte of the curve order to be distinct
+ * from 0 and 1.
+ */
+ const br_ec_curve_def *cd;
+ uint32_t n[I31_LEN], r[I31_LEN], s[I31_LEN], x[I31_LEN];
+ uint32_t m[I31_LEN], k[I31_LEN], t1[I31_LEN], t2[I31_LEN];
+ unsigned char tt[ORDER_LEN << 1];
+ unsigned char eU[POINT_LEN];
+ size_t hash_len, nlen, ulen;
+ uint32_t n0i, ctl;
+ br_hmac_drbg_context drbg;
+
+ /*
+ * Get the curve parameters (generator and order).
+ */
+ switch (sk->curve) {
+ case BR_EC_secp256r1:
+ cd = &br_secp256r1;
+ break;
+ case BR_EC_secp384r1:
+ cd = &br_secp384r1;
+ break;
+ case BR_EC_secp521r1:
+ cd = &br_secp521r1;
+ break;
+ default:
+ return 0;
+ }
+
+ /*
+ * Get modulus.
+ */
+ nlen = cd->order_len;
+ br_i31_decode(n, cd->order, nlen);
+ n0i = br_i31_ninv31(n[1]);
+
+ /*
+ * Get private key as an i31 integer. This also checks that the
+ * private key is well-defined (not zero, and less than the
+ * curve order).
+ */
+ if (!br_i31_decode_mod(x, sk->x, sk->xlen, n)) {
+ return 0;
+ }
+ if (br_i31_iszero(x)) {
+ return 0;
+ }
+
+ /*
+ * Get hash length.
+ */
+ hash_len = (hf->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK;
+
+ /*
+ * Truncate and reduce the hash value modulo the curve order.
+ */
+ br_ecdsa_i31_bits2int(m, hash_value, hash_len, n[0]);
+ br_i31_sub(m, n, br_i31_sub(m, n, 0) ^ 1);
+
+ /*
+ * RFC 6979 generation of the "k" value.
+ *
+ * The process uses HMAC_DRBG (with the hash function used to
+ * process the message that is to be signed). The seed is the
+ * concatenation of the encodings of the private key and
+ * the hash value (after truncation and modular reduction).
+ */
+ br_i31_encode(tt, nlen, x);
+ br_i31_encode(tt + nlen, nlen, m);
+ br_hmac_drbg_init(&drbg, hf, tt, nlen << 1);
+ for (;;) {
+ br_hmac_drbg_generate(&drbg, tt, nlen);
+ br_ecdsa_i31_bits2int(k, tt, nlen, n[0]);
+ if (br_i31_iszero(k)) {
+ continue;
+ }
+ if (br_i31_sub(k, n, 0)) {
+ break;
+ }
+ }
+
+ /*
+ * Compute k*G and extract the X coordinate, then reduce it
+ * modulo the curve order. Since we support only curves with
+ * prime order, that reduction is only a matter of computing
+ * a subtraction.
+ */
+ ulen = cd->generator_len;
+ memcpy(eU, cd->generator, ulen);
+ br_i31_encode(tt, nlen, k);
+ if (!impl->mul(eU, ulen, tt, nlen, sk->curve)) {
+ /*
+ * Point multiplication may fail here only if the
+ * EC implementation does not support the curve, or the
+ * private key is incorrect (x is a multiple of the curve
+ * order).
+ */
+ return 0;
+ }
+ br_i31_zero(r, n[0]);
+ br_i31_decode(r, &eU[1], ulen >> 1);
+ r[0] = n[0];
+ br_i31_sub(r, n, br_i31_sub(r, n, 0) ^ 1);
+
+ /*
+ * Compute 1/k in double-Montgomery representation. We do so by
+ * first converting _from_ Montgomery representation (twice),
+ * then using a modular exponentiation.
+ */
+ br_i31_from_monty(k, n, n0i);
+ br_i31_from_monty(k, n, n0i);
+ memcpy(tt, cd->order, nlen);
+ tt[nlen - 1] -= 2;
+ br_i31_modpow(k, tt, nlen, n, n0i, t1, t2);
+
+ /*
+ * Compute s = (m+xr)/k (mod n).
+ * The k[] array contains R^2/k (double-Montgomery representation);
+ * we thus can use direct Montgomery multiplications and conversions
+ * from Montgomery, avoiding any call to br_i31_to_monty() (which
+ * is slower).
+ */
+ br_i31_from_monty(m, n, n0i);
+ br_i31_montymul(t1, x, r, n, n0i);
+ ctl = br_i31_add(t1, m, 1);
+ ctl |= br_i31_sub(t1, n, 0) ^ 1;
+ br_i31_sub(t1, n, ctl);
+ br_i31_montymul(s, t1, k, n, n0i);
+
+ /*
+ * Encode r and s in the signature.
+ */
+ br_i31_encode(sig, nlen, r);
+ br_i31_encode((unsigned char *)sig + nlen, nlen, s);
+ return nlen << 1;
+}
--- /dev/null
+/*
+ * 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"
+
+#define FIELD_LEN ((BR_MAX_EC_SIZE + 7) >> 3)
+
+/* see bearssl_ec.h */
+uint32_t
+br_ecdsa_i31_vrfy_asn1(const br_ec_impl *impl,
+ const void *hash, size_t hash_len,
+ const br_ec_public_key *pk,
+ const void *sig, size_t sig_len)
+{
+ unsigned char rsig[(FIELD_LEN << 1) + 12];
+
+ if (sig_len > sizeof rsig) {
+ return 0;
+ }
+ memcpy(rsig, sig, sig_len);
+ sig_len = br_ecdsa_asn1_to_raw(rsig, sig_len);
+ return br_ecdsa_i31_vrfy_raw(impl, hash, hash_len, pk, rsig, sig_len);
+}
--- /dev/null
+/*
+ * 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"
+
+#define I31_LEN ((BR_MAX_EC_SIZE + 61) / 31)
+#define POINT_LEN (1 + (((BR_MAX_EC_SIZE + 7) >> 3) << 1))
+
+/* see bearssl_ec.h */
+uint32_t
+br_ecdsa_i31_vrfy_raw(const br_ec_impl *impl,
+ const void *hash, size_t hash_len,
+ const br_ec_public_key *pk,
+ const void *sig, size_t sig_len)
+{
+ /*
+ * IMPORTANT: this code is fit only for curves with a prime
+ * order. This is needed so that modular reduction of the X
+ * coordinate of a point can be done with a simple subtraction.
+ */
+ const br_ec_curve_def *cd;
+ uint32_t n[I31_LEN], r[I31_LEN], s[I31_LEN], t1[I31_LEN], t2[I31_LEN];
+ unsigned char tx[(BR_MAX_EC_SIZE + 7) >> 3];
+ unsigned char ty[(BR_MAX_EC_SIZE + 7) >> 3];
+ unsigned char eU[POINT_LEN];
+ size_t nlen, rlen, ulen;
+ uint32_t n0i, res;
+
+ /*
+ * Get the curve parameters (generator and order).
+ */
+ switch (pk->curve) {
+ case BR_EC_secp256r1:
+ cd = &br_secp256r1;
+ break;
+ case BR_EC_secp384r1:
+ cd = &br_secp384r1;
+ break;
+ case BR_EC_secp521r1:
+ cd = &br_secp521r1;
+ break;
+ default:
+ return 0;
+ }
+
+ /*
+ * Signature length must be even.
+ */
+ if (sig_len & 1) {
+ return 0;
+ }
+ rlen = sig_len >> 1;
+
+ /*
+ * Public key point must have the proper size for this curve.
+ */
+ if (pk->qlen != cd->generator_len) {
+ return 0;
+ }
+
+ /*
+ * Get modulus; then decode the r and s values. They must be
+ * lower than the modulus, and s must not be null.
+ */
+ nlen = cd->order_len;
+ br_i31_decode(n, cd->order, nlen);
+ n0i = br_i31_ninv31(n[1]);
+ if (!br_i31_decode_mod(r, sig, rlen, n)) {
+ return 0;
+ }
+ if (!br_i31_decode_mod(s, (const unsigned char *)sig + rlen, rlen, n)) {
+ return 0;
+ }
+ if (br_i31_iszero(s)) {
+ return 0;
+ }
+
+ /*
+ * Invert s. We do that with a modular exponentiation; we use
+ * the fact that for all the curves we support, the least
+ * significant byte is not 0 or 1, so we can subtract 2 without
+ * any carry to process.
+ * We also want 1/s in Montgomery representation, which can be
+ * done by converting _from_ Montgomery representation before
+ * the inversion (because (1/s)*R = 1/(s/R)).
+ */
+ br_i31_from_monty(s, n, n0i);
+ memcpy(tx, cd->order, nlen);
+ tx[nlen - 1] -= 2;
+ br_i31_modpow(s, tx, nlen, n, n0i, t1, t2);
+
+ /*
+ * Truncate the hash to the modulus length (in bits) and reduce
+ * it modulo the curve order. The modular reduction can be done
+ * with a subtraction since the truncation already reduced the
+ * value to the modulus bit length.
+ */
+ br_ecdsa_i31_bits2int(t1, hash, hash_len, n[0]);
+ br_i31_sub(t1, n, br_i31_sub(t1, n, 0) ^ 1);
+
+ /*
+ * Multiply the (truncated, reduced) hash value with 1/s, result in
+ * t2, encoded in ty.
+ */
+ br_i31_montymul(t2, t1, s, n, n0i);
+ br_i31_encode(ty, nlen, t2);
+
+ /*
+ * Multiply r with 1/s, result in t1, encoded in tx.
+ */
+ br_i31_montymul(t1, r, s, n, n0i);
+ br_i31_encode(tx, nlen, t1);
+
+ /*
+ * Compute the point x*Q + y*G.
+ */
+ ulen = cd->generator_len;
+ memcpy(eU, pk->q, ulen);
+ res = impl->muladd(eU, cd->generator, ulen,
+ tx, nlen, ty, nlen, cd->curve);
+
+ /*
+ * Get the X coordinate, reduce modulo the curve order, and
+ * compare with the 'r' value.
+ *
+ * The modular reduction can be done with subtractions because
+ * we work with curves of prime order, so the curve order is
+ * close to the field order (Hasse's theorem).
+ */
+ br_i31_zero(t1, n[0]);
+ br_i31_decode(t1, &eU[1], ulen >> 1);
+ t1[0] = n[0];
+ br_i31_sub(t1, n, br_i31_sub(t1, n, 0) ^ 1);
+ res &= ~br_i31_sub(t1, r, 1);
+ res &= br_i31_iszero(t1);
+ return res;
+}
--- /dev/null
+/*
+ * 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"
+
+static size_t
+asn1_int_length(const unsigned char *x, size_t xlen)
+{
+ while (xlen > 0 && *x == 0) {
+ x ++;
+ xlen --;
+ }
+ if (xlen == 0 || *x >= 0x80) {
+ xlen ++;
+ }
+ return xlen;
+}
+
+/* see bearssl_ec.h */
+size_t
+br_ecdsa_raw_to_asn1(void *sig, size_t sig_len)
+{
+ /*
+ * Internal buffer is large enough to accommodate a signature
+ * such that r and s fit on 125 bytes each (signed encoding),
+ * meaning a curve order of up to 1000 bits. This is the limit
+ * that ensures "simple" length encodings.
+ */
+ unsigned char *buf;
+ size_t hlen, rlen, slen, zlen, off;
+ unsigned char tmp[257];
+
+ buf = sig;
+ if ((sig_len & 1) != 0) {
+ return 0;
+ }
+ hlen = sig_len >> 1;
+ rlen = asn1_int_length(buf, hlen);
+ slen = asn1_int_length(buf + hlen, hlen);
+ if (rlen > 125 || slen > 125) {
+ return 0;
+ }
+ tmp[0] = 0x30;
+ zlen = rlen + slen + 4;
+ if (zlen >= 0x80) {
+ tmp[1] = 0x81;
+ tmp[2] = zlen;
+ off = 3;
+ } else {
+ tmp[1] = zlen;
+ off = 2;
+ }
+ tmp[off ++] = 0x02;
+ tmp[off ++] = rlen;
+ if (rlen > hlen) {
+ tmp[off] = 0x00;
+ memcpy(tmp + off + 1, buf, hlen);
+ } else {
+ memcpy(tmp + off, buf + hlen - rlen, rlen);
+ }
+ off += rlen;
+ tmp[off ++] = 0x02;
+ tmp[off ++] = slen;
+ if (slen > hlen) {
+ tmp[off] = 0x00;
+ memcpy(tmp + off + 1, buf + hlen, hlen);
+ } else {
+ memcpy(tmp + off, buf + sig_len - slen, slen);
+ }
+ off += slen;
+ memcpy(sig, tmp, off);
+ return off;
+}
--- /dev/null
+/*
+ * 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"
+
+static const unsigned char md5_OID[] = {
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05
+};
+
+static const unsigned char sha1_OID[] = {
+ 0x2B, 0x0E, 0x03, 0x02, 0x1A
+};
+
+static const unsigned char sha224_OID[] = {
+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04
+};
+
+static const unsigned char sha256_OID[] = {
+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01
+};
+
+static const unsigned char sha384_OID[] = {
+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02
+};
+
+static const unsigned char sha512_OID[] = {
+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03
+};
+
+/* see inner.h */
+const unsigned char *
+br_digest_OID(int digest_id, size_t *len)
+{
+ switch (digest_id) {
+ case br_md5_ID:
+ *len = sizeof md5_OID;
+ return md5_OID;
+ case br_sha1_ID:
+ *len = sizeof sha1_OID;
+ return sha1_OID;
+ case br_sha224_ID:
+ *len = sizeof sha224_OID;
+ return sha224_OID;
+ case br_sha256_ID:
+ *len = sizeof sha256_OID;
+ return sha256_OID;
+ case br_sha384_ID:
+ *len = sizeof sha384_OID;
+ return sha384_OID;
+ case br_sha512_ID:
+ *len = sizeof sha512_OID;
+ return sha512_OID;
+ default:
+ *len = 0;
+ return NULL;
+ }
+}
--- /dev/null
+/*
+ * 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 inner.h */
+size_t
+br_digest_size_by_ID(int digest_id)
+{
+ switch (digest_id) {
+ case br_md5sha1_ID:
+ return br_md5_SIZE + br_sha1_SIZE;
+ case br_md5_ID:
+ return br_md5_SIZE;
+ case br_sha1_ID:
+ return br_sha1_SIZE;
+ case br_sha224_ID:
+ return br_sha224_SIZE;
+ case br_sha256_ID:
+ return br_sha256_SIZE;
+ case br_sha384_ID:
+ return br_sha384_SIZE;
+ case br_sha512_ID:
+ return br_sha512_SIZE;
+ default:
+ /* abort(); */
+ return 0;
+ }
+}
--- /dev/null
+/*
+ * 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"
+
+/*
+ * We compute "carryless multiplications" through normal integer
+ * multiplications, masking out enough bits to create "holes" in which
+ * carries may expand without altering our bits; we really use 8 data
+ * bits per 32-bit word, space every fourth bit. Accumulated carries
+ * may not exceed 8 in total, which fits in 4 bits.
+ *
+ * It would be possible to use a 3-bit spacing, allowing two operands,
+ * one with 7 non-zero data bits, the other one with 10 or 11 non-zero
+ * data bits; this asymmetric splitting makes the overall code more
+ * complex with thresholds and exceptions, and does not appear to be
+ * worth the effort.
+ */
+
+/*
+ * We cannot really autodetect whether multiplications are "slow" or
+ * not. A typical example is the ARM Cortex M0+, which exists in two
+ * versions: one with a 1-cycle multiplication opcode, the other with
+ * a 32-cycle multiplication opcodes. They both use exactly the same
+ * architecture and ABI, and cannot be distinguished from each other
+ * at compile-time.
+ *
+ * Since most modern CPU (even embedded CPU) still have fast
+ * multiplications, we use the "fast mul" code by default.
+ */
+
+#if BR_SLOW_MUL
+
+/*
+ * This implementation uses Karatsuba-like reduction to make fewer
+ * integer multiplications (9 instead of 16), at the expense of extra
+ * logical operations (XOR, shifts...). On modern x86 CPU that offer
+ * fast, pipelined multiplications, this code is about twice slower than
+ * the simpler code with 16 multiplications. This tendency may be
+ * reversed on low-end platforms with expensive multiplications.
+ */
+
+#define MUL32(h, l, x, y) do { \
+ uint64_t mul32tmp = MUL(x, y); \
+ (h) = (uint32_t)(mul32tmp >> 32); \
+ (l) = (uint32_t)mul32tmp; \
+ } while (0)
+
+static inline void
+bmul(uint32_t *hi, uint32_t *lo, uint32_t x, uint32_t y)
+{
+ uint32_t x0, x1, x2, x3;
+ uint32_t y0, y1, y2, y3;
+ uint32_t a0, a1, a2, a3, a4, a5, a6, a7, a8;
+ uint32_t b0, b1, b2, b3, b4, b5, b6, b7, b8;
+
+ x0 = x & (uint32_t)0x11111111;
+ x1 = x & (uint32_t)0x22222222;
+ x2 = x & (uint32_t)0x44444444;
+ x3 = x & (uint32_t)0x88888888;
+ y0 = y & (uint32_t)0x11111111;
+ y1 = y & (uint32_t)0x22222222;
+ y2 = y & (uint32_t)0x44444444;
+ y3 = y & (uint32_t)0x88888888;
+
+ /*
+ * (x0+W*x1)*(y0+W*y1) -> a0:b0
+ * (x2+W*x3)*(y2+W*y3) -> a3:b3
+ * ((x0+x2)+W*(x1+x3))*((y0+y2)+W*(y1+y3)) -> a6:b6
+ */
+ a0 = x0;
+ b0 = y0;
+ a1 = x1 >> 1;
+ b1 = y1 >> 1;
+ a2 = a0 ^ a1;
+ b2 = b0 ^ b1;
+ a3 = x2 >> 2;
+ b3 = y2 >> 2;
+ a4 = x3 >> 3;
+ b4 = y3 >> 3;
+ a5 = a3 ^ a4;
+ b5 = b3 ^ b4;
+ a6 = a0 ^ a3;
+ b6 = b0 ^ b3;
+ a7 = a1 ^ a4;
+ b7 = b1 ^ b4;
+ a8 = a6 ^ a7;
+ b8 = b6 ^ b7;
+
+ MUL32(b0, a0, b0, a0);
+ MUL32(b1, a1, b1, a1);
+ MUL32(b2, a2, b2, a2);
+ MUL32(b3, a3, b3, a3);
+ MUL32(b4, a4, b4, a4);
+ MUL32(b5, a5, b5, a5);
+ MUL32(b6, a6, b6, a6);
+ MUL32(b7, a7, b7, a7);
+ MUL32(b8, a8, b8, a8);
+
+ a0 &= (uint32_t)0x11111111;
+ a1 &= (uint32_t)0x11111111;
+ a2 &= (uint32_t)0x11111111;
+ a3 &= (uint32_t)0x11111111;
+ a4 &= (uint32_t)0x11111111;
+ a5 &= (uint32_t)0x11111111;
+ a6 &= (uint32_t)0x11111111;
+ a7 &= (uint32_t)0x11111111;
+ a8 &= (uint32_t)0x11111111;
+ b0 &= (uint32_t)0x11111111;
+ b1 &= (uint32_t)0x11111111;
+ b2 &= (uint32_t)0x11111111;
+ b3 &= (uint32_t)0x11111111;
+ b4 &= (uint32_t)0x11111111;
+ b5 &= (uint32_t)0x11111111;
+ b6 &= (uint32_t)0x11111111;
+ b7 &= (uint32_t)0x11111111;
+ b8 &= (uint32_t)0x11111111;
+
+ a2 ^= a0 ^ a1;
+ b2 ^= b0 ^ b1;
+ a0 ^= (a2 << 1) ^ (a1 << 2);
+ b0 ^= (b2 << 1) ^ (b1 << 2);
+ a5 ^= a3 ^ a4;
+ b5 ^= b3 ^ b4;
+ a3 ^= (a5 << 1) ^ (a4 << 2);
+ b3 ^= (b5 << 1) ^ (b4 << 2);
+ a8 ^= a6 ^ a7;
+ b8 ^= b6 ^ b7;
+ a6 ^= (a8 << 1) ^ (a7 << 2);
+ b6 ^= (b8 << 1) ^ (b7 << 2);
+ a6 ^= a0 ^ a3;
+ b6 ^= b0 ^ b3;
+ *lo = a0 ^ (a6 << 2) ^ (a3 << 4);
+ *hi = b0 ^ (b6 << 2) ^ (b3 << 4) ^ (a6 >> 30) ^ (a3 >> 28);
+}
+
+#else
+
+/*
+ * Simple multiplication in GF(2)[X], using 16 integer multiplications.
+ */
+
+static inline void
+bmul(uint32_t *hi, uint32_t *lo, uint32_t x, uint32_t y)
+{
+ uint32_t x0, x1, x2, x3;
+ uint32_t y0, y1, y2, y3;
+ uint64_t z0, z1, z2, z3;
+ uint64_t z;
+
+ x0 = x & (uint32_t)0x11111111;
+ x1 = x & (uint32_t)0x22222222;
+ x2 = x & (uint32_t)0x44444444;
+ x3 = x & (uint32_t)0x88888888;
+ y0 = y & (uint32_t)0x11111111;
+ y1 = y & (uint32_t)0x22222222;
+ y2 = y & (uint32_t)0x44444444;
+ y3 = y & (uint32_t)0x88888888;
+ z0 = MUL(x0, y0) ^ MUL(x1, y3) ^ MUL(x2, y2) ^ MUL(x3, y1);
+ z1 = MUL(x0, y1) ^ MUL(x1, y0) ^ MUL(x2, y3) ^ MUL(x3, y2);
+ z2 = MUL(x0, y2) ^ MUL(x1, y1) ^ MUL(x2, y0) ^ MUL(x3, y3);
+ z3 = MUL(x0, y3) ^ MUL(x1, y2) ^ MUL(x2, y1) ^ MUL(x3, y0);
+ z0 &= (uint64_t)0x1111111111111111;
+ z1 &= (uint64_t)0x2222222222222222;
+ z2 &= (uint64_t)0x4444444444444444;
+ z3 &= (uint64_t)0x8888888888888888;
+ z = z0 | z1 | z2 | z3;
+ *lo = (uint32_t)z;
+ *hi = (uint32_t)(z >> 32);
+}
+
+#endif
+
+/* see bearssl_hash.h */
+void
+br_ghash_ctmul(void *y, const void *h, const void *data, size_t len)
+{
+ const unsigned char *buf, *hb;
+ unsigned char *yb;
+ uint32_t yw[4];
+ uint32_t hw[4];
+
+ buf = data;
+ yb = y;
+ hb = h;
+ yw[3] = br_dec32be(yb);
+ yw[2] = br_dec32be(yb + 4);
+ yw[1] = br_dec32be(yb + 8);
+ yw[0] = br_dec32be(yb + 12);
+ hw[3] = br_dec32be(hb);
+ hw[2] = br_dec32be(hb + 4);
+ hw[1] = br_dec32be(hb + 8);
+ hw[0] = br_dec32be(hb + 12);
+ while (len > 0) {
+ const unsigned char *src;
+ unsigned char tmp[16];
+ int i;
+ uint32_t a[9], b[9], zw[8];
+ uint32_t c0, c1, c2, c3, d0, d1, d2, d3, e0, e1, e2, e3;
+
+ if (len >= 16) {
+ src = buf;
+ buf += 16;
+ len -= 16;
+ } else {
+ memcpy(tmp, buf, len);
+ memset(tmp + len, 0, (sizeof tmp) - len);
+ src = tmp;
+ len = 0;
+ }
+ yw[3] ^= br_dec32be(src);
+ yw[2] ^= br_dec32be(src + 4);
+ yw[1] ^= br_dec32be(src + 8);
+ yw[0] ^= br_dec32be(src + 12);
+
+ /*
+ * y[0,1]*h[0,1] -> 0..2
+ * y[2,3]*h[2,3] -> 3..5
+ * (y[0,1]+y[2,3])*(h[0,1]+h[2,3]) -> 6..8
+ */
+ a[0] = yw[0];
+ b[0] = hw[0];
+ a[1] = yw[1];
+ b[1] = hw[1];
+ a[2] = a[0] ^ a[1];
+ b[2] = b[0] ^ b[1];
+
+ a[3] = yw[2];
+ b[3] = hw[2];
+ a[4] = yw[3];
+ b[4] = hw[3];
+ a[5] = a[3] ^ a[4];
+ b[5] = b[3] ^ b[4];
+
+ a[6] = a[0] ^ a[3];
+ b[6] = b[0] ^ b[3];
+ a[7] = a[1] ^ a[4];
+ b[7] = b[1] ^ b[4];
+ a[8] = a[6] ^ a[7];
+ b[8] = b[6] ^ b[7];
+
+ for (i = 0; i < 9; i ++) {
+ bmul(&b[i], &a[i], b[i], a[i]);
+ }
+
+ c0 = a[0];
+ c1 = b[0] ^ a[2] ^ a[0] ^ a[1];
+ c2 = a[1] ^ b[2] ^ b[0] ^ b[1];
+ c3 = b[1];
+ d0 = a[3];
+ d1 = b[3] ^ a[5] ^ a[3] ^ a[4];
+ d2 = a[4] ^ b[5] ^ b[3] ^ b[4];
+ d3 = b[4];
+ e0 = a[6];
+ e1 = b[6] ^ a[8] ^ a[6] ^ a[7];
+ e2 = a[7] ^ b[8] ^ b[6] ^ b[7];
+ e3 = b[7];
+
+ e0 ^= c0 ^ d0;
+ e1 ^= c1 ^ d1;
+ e2 ^= c2 ^ d2;
+ e3 ^= c3 ^ d3;
+ c2 ^= e0;
+ c3 ^= e1;
+ d0 ^= e2;
+ d1 ^= e3;
+
+ zw[0] = c0 << 1;
+ zw[1] = (c1 << 1) | (c0 >> 31);
+ zw[2] = (c2 << 1) | (c1 >> 31);
+ zw[3] = (c3 << 1) | (c2 >> 31);
+ zw[4] = (d0 << 1) | (c3 >> 31);
+ zw[5] = (d1 << 1) | (d0 >> 31);
+ zw[6] = (d2 << 1) | (d1 >> 31);
+ zw[7] = (d3 << 1) | (d2 >> 31);
+
+ for (i = 0; i < 4; i ++) {
+ uint32_t lw;
+
+ lw = zw[i];
+ zw[i + 4] ^= lw ^ (lw >> 1) ^ (lw >> 2) ^ (lw >> 7);
+ zw[i + 3] ^= (lw << 31) ^ (lw << 30) ^ (lw << 25);
+ }
+ memcpy(yw, zw + 4, sizeof yw);
+ }
+ br_enc32be(yb, yw[3]);
+ br_enc32be(yb + 4, yw[2]);
+ br_enc32be(yb + 8, yw[1]);
+ br_enc32be(yb + 12, yw[0]);
+}
--- /dev/null
+/*
+ * 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"
+
+/*
+ * This implementation uses 32-bit multiplications, and only the low
+ * 32 bits for each multiplication result. This is meant primarily for
+ * the ARM Cortex M0 and M0+, whose multiplication opcode does not yield
+ * the upper 32 bits; but it might also be useful on architectures where
+ * access to the upper 32 bits requires use of specific registers that
+ * create contention (e.g. on i386, "mul" necessarily outputs the result
+ * in edx:eax, while "imul" can use any registers but is limited to the
+ * low 32 bits).
+ *
+ * The implementation trick that is used here is bit-reversing (bit 0
+ * is swapped with bit 31, bit 1 with bit 30, and so on). In GF(2)[X],
+ * for all values x and y, we have:
+ * rev32(x) * rev32(y) = rev64(x * y)
+ * In other words, if we bit-reverse (over 32 bits) the operands, then we
+ * bit-reverse (over 64 bits) the result.
+ */
+
+/*
+ * Multiplication in GF(2)[X], truncated to its low 32 bits.
+ */
+static inline uint32_t
+bmul32(uint32_t x, uint32_t y)
+{
+ uint32_t x0, x1, x2, x3;
+ uint32_t y0, y1, y2, y3;
+ uint32_t z0, z1, z2, z3;
+
+ x0 = x & (uint32_t)0x11111111;
+ x1 = x & (uint32_t)0x22222222;
+ x2 = x & (uint32_t)0x44444444;
+ x3 = x & (uint32_t)0x88888888;
+ y0 = y & (uint32_t)0x11111111;
+ y1 = y & (uint32_t)0x22222222;
+ y2 = y & (uint32_t)0x44444444;
+ y3 = y & (uint32_t)0x88888888;
+ z0 = (x0 * y0) ^ (x1 * y3) ^ (x2 * y2) ^ (x3 * y1);
+ z1 = (x0 * y1) ^ (x1 * y0) ^ (x2 * y3) ^ (x3 * y2);
+ z2 = (x0 * y2) ^ (x1 * y1) ^ (x2 * y0) ^ (x3 * y3);
+ z3 = (x0 * y3) ^ (x1 * y2) ^ (x2 * y1) ^ (x3 * y0);
+ z0 &= (uint32_t)0x11111111;
+ z1 &= (uint32_t)0x22222222;
+ z2 &= (uint32_t)0x44444444;
+ z3 &= (uint32_t)0x88888888;
+ return z0 | z1 | z2 | z3;
+}
+
+/*
+ * Bit-reverse a 32-bit word.
+ */
+static uint32_t
+rev32(uint32_t x)
+{
+#define RMS(m, s) do { \
+ x = ((x & (uint32_t)(m)) << (s)) \
+ | ((x >> (s)) & (uint32_t)(m)); \
+ } while (0)
+
+ RMS(0x55555555, 1);
+ RMS(0x33333333, 2);
+ RMS(0x0F0F0F0F, 4);
+ RMS(0x00FF00FF, 8);
+ return (x << 16) | (x >> 16);
+
+#undef RMS
+}
+
+/* see bearssl_hash.h */
+void
+br_ghash_ctmul32(void *y, const void *h, const void *data, size_t len)
+{
+ const unsigned char *buf, *hb;
+ unsigned char *yb;
+ uint32_t yw[4];
+ uint32_t hw[4], hwr[4];
+
+ buf = data;
+ yb = y;
+ hb = h;
+ yw[3] = br_dec32be(yb);
+ yw[2] = br_dec32be(yb + 4);
+ yw[1] = br_dec32be(yb + 8);
+ yw[0] = br_dec32be(yb + 12);
+ hw[3] = br_dec32be(hb);
+ hw[2] = br_dec32be(hb + 4);
+ hw[1] = br_dec32be(hb + 8);
+ hw[0] = br_dec32be(hb + 12);
+ hwr[3] = rev32(hw[3]);
+ hwr[2] = rev32(hw[2]);
+ hwr[1] = rev32(hw[1]);
+ hwr[0] = rev32(hw[0]);
+ while (len > 0) {
+ const unsigned char *src;
+ unsigned char tmp[16];
+ int i;
+ uint32_t a[18], b[18], c[18];
+ uint32_t d0, d1, d2, d3, d4, d5, d6, d7;
+ uint32_t zw[8];
+
+ if (len >= 16) {
+ src = buf;
+ buf += 16;
+ len -= 16;
+ } else {
+ memcpy(tmp, buf, len);
+ memset(tmp + len, 0, (sizeof tmp) - len);
+ src = tmp;
+ len = 0;
+ }
+ yw[3] ^= br_dec32be(src);
+ yw[2] ^= br_dec32be(src + 4);
+ yw[1] ^= br_dec32be(src + 8);
+ yw[0] ^= br_dec32be(src + 12);
+
+ /*
+ * We are using Karatsuba: the 128x128 multiplication is
+ * reduced to three 64x64 multiplications, hence nine
+ * 32x32 multiplications. With the bit-reversal trick,
+ * we have to perform 18 32x32 multiplications.
+ */
+
+ /*
+ * y[0,1]*h[0,1] -> 0,1,4
+ * y[2,3]*h[2,3] -> 2,3,5
+ * (y[0,1]+y[2,3])*(h[0,1]+h[2,3]) -> 6,7,8
+ */
+
+ a[0] = yw[0];
+ a[1] = yw[1];
+ a[2] = yw[2];
+ a[3] = yw[3];
+ a[4] = a[0] ^ a[1];
+ a[5] = a[2] ^ a[3];
+ a[6] = a[0] ^ a[2];
+ a[7] = a[1] ^ a[3];
+ a[8] = a[6] ^ a[7];
+
+ a[ 9] = rev32(yw[0]);
+ a[10] = rev32(yw[1]);
+ a[11] = rev32(yw[2]);
+ a[12] = rev32(yw[3]);
+ a[13] = a[ 9] ^ a[10];
+ a[14] = a[11] ^ a[12];
+ a[15] = a[ 9] ^ a[11];
+ a[16] = a[10] ^ a[12];
+ a[17] = a[15] ^ a[16];
+
+ b[0] = hw[0];
+ b[1] = hw[1];
+ b[2] = hw[2];
+ b[3] = hw[3];
+ b[4] = b[0] ^ b[1];
+ b[5] = b[2] ^ b[3];
+ b[6] = b[0] ^ b[2];
+ b[7] = b[1] ^ b[3];
+ b[8] = b[6] ^ b[7];
+
+ b[ 9] = hwr[0];
+ b[10] = hwr[1];
+ b[11] = hwr[2];
+ b[12] = hwr[3];
+ b[13] = b[ 9] ^ b[10];
+ b[14] = b[11] ^ b[12];
+ b[15] = b[ 9] ^ b[11];
+ b[16] = b[10] ^ b[12];
+ b[17] = b[15] ^ b[16];
+
+ for (i = 0; i < 18; i ++) {
+ c[i] = bmul32(a[i], b[i]);
+ }
+
+ c[4] ^= c[0] ^ c[1];
+ c[5] ^= c[2] ^ c[3];
+ c[8] ^= c[6] ^ c[7];
+
+ c[13] ^= c[ 9] ^ c[10];
+ c[14] ^= c[11] ^ c[12];
+ c[17] ^= c[15] ^ c[16];
+
+ /*
+ * y[0,1]*h[0,1] -> 0,9^4,1^13,10
+ * y[2,3]*h[2,3] -> 2,11^5,3^14,12
+ * (y[0,1]+y[2,3])*(h[0,1]+h[2,3]) -> 6,15^8,7^17,16
+ */
+ d0 = c[0];
+ d1 = c[4] ^ (rev32(c[9]) >> 1);
+ d2 = c[1] ^ c[0] ^ c[2] ^ c[6] ^ (rev32(c[13]) >> 1);
+ d3 = c[4] ^ c[5] ^ c[8]
+ ^ (rev32(c[10] ^ c[9] ^ c[11] ^ c[15]) >> 1);
+ d4 = c[2] ^ c[1] ^ c[3] ^ c[7]
+ ^ (rev32(c[13] ^ c[14] ^ c[17]) >> 1);
+ d5 = c[5] ^ (rev32(c[11] ^ c[10] ^ c[12] ^ c[16]) >> 1);
+ d6 = c[3] ^ (rev32(c[14]) >> 1);
+ d7 = rev32(c[12]) >> 1;
+
+ zw[0] = d0 << 1;
+ zw[1] = (d1 << 1) | (d0 >> 31);
+ zw[2] = (d2 << 1) | (d1 >> 31);
+ zw[3] = (d3 << 1) | (d2 >> 31);
+ zw[4] = (d4 << 1) | (d3 >> 31);
+ zw[5] = (d5 << 1) | (d4 >> 31);
+ zw[6] = (d6 << 1) | (d5 >> 31);
+ zw[7] = (d7 << 1) | (d6 >> 31);
+
+ for (i = 0; i < 4; i ++) {
+ uint32_t lw;
+
+ lw = zw[i];
+ zw[i + 4] ^= lw ^ (lw >> 1) ^ (lw >> 2) ^ (lw >> 7);
+ zw[i + 3] ^= (lw << 31) ^ (lw << 30) ^ (lw << 25);
+ }
+ memcpy(yw, zw + 4, sizeof yw);
+ }
+ br_enc32be(yb, yw[3]);
+ br_enc32be(yb + 4, yw[2]);
+ br_enc32be(yb + 8, yw[1]);
+ br_enc32be(yb + 12, yw[0]);
+}
--- /dev/null
+/*
+ * 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"
+
+/*
+ * This is the 64-bit variant of ghash_ctmul32(), with 64-bit operands
+ * and bit reversal of 64-bit words.
+ */
+
+static inline uint64_t
+bmul64(uint64_t x, uint64_t y)
+{
+ uint64_t x0, x1, x2, x3;
+ uint64_t y0, y1, y2, y3;
+ uint64_t z0, z1, z2, z3;
+
+ x0 = x & (uint64_t)0x1111111111111111;
+ x1 = x & (uint64_t)0x2222222222222222;
+ x2 = x & (uint64_t)0x4444444444444444;
+ x3 = x & (uint64_t)0x8888888888888888;
+ y0 = y & (uint64_t)0x1111111111111111;
+ y1 = y & (uint64_t)0x2222222222222222;
+ y2 = y & (uint64_t)0x4444444444444444;
+ y3 = y & (uint64_t)0x8888888888888888;
+ z0 = (x0 * y0) ^ (x1 * y3) ^ (x2 * y2) ^ (x3 * y1);
+ z1 = (x0 * y1) ^ (x1 * y0) ^ (x2 * y3) ^ (x3 * y2);
+ z2 = (x0 * y2) ^ (x1 * y1) ^ (x2 * y0) ^ (x3 * y3);
+ z3 = (x0 * y3) ^ (x1 * y2) ^ (x2 * y1) ^ (x3 * y0);
+ z0 &= (uint64_t)0x1111111111111111;
+ z1 &= (uint64_t)0x2222222222222222;
+ z2 &= (uint64_t)0x4444444444444444;
+ z3 &= (uint64_t)0x8888888888888888;
+ return z0 | z1 | z2 | z3;
+}
+
+static uint64_t
+rev64(uint64_t x)
+{
+#define RMS(m, s) do { \
+ x = ((x & (uint64_t)(m)) << (s)) \
+ | ((x >> (s)) & (uint64_t)(m)); \
+ } while (0)
+
+ RMS(0x5555555555555555, 1);
+ RMS(0x3333333333333333, 2);
+ RMS(0x0F0F0F0F0F0F0F0F, 4);
+ RMS(0x00FF00FF00FF00FF, 8);
+ RMS(0x0000FFFF0000FFFF, 16);
+ return (x << 32) | (x >> 32);
+
+#undef RMS
+}
+
+/* see bearssl_ghash.h */
+void
+br_ghash_ctmul64(void *y, const void *h, const void *data, size_t len)
+{
+ const unsigned char *buf, *hb;
+ unsigned char *yb;
+ uint64_t y0, y1;
+ uint64_t h0, h1, h2, h0r, h1r, h2r;
+
+ buf = data;
+ yb = y;
+ hb = h;
+ y1 = br_dec64be(yb);
+ y0 = br_dec64be(yb + 8);
+ h1 = br_dec64be(hb);
+ h0 = br_dec64be(hb + 8);
+ h0r = rev64(h0);
+ h1r = rev64(h1);
+ h2 = h0 ^ h1;
+ h2r = h0r ^ h1r;
+ while (len > 0) {
+ const unsigned char *src;
+ unsigned char tmp[16];
+ uint64_t y0r, y1r, y2, y2r;
+ uint64_t z0, z1, z2, z0h, z1h, z2h;
+ uint64_t v0, v1, v2, v3;
+
+ if (len >= 16) {
+ src = buf;
+ buf += 16;
+ len -= 16;
+ } else {
+ memcpy(tmp, buf, len);
+ memset(tmp + len, 0, (sizeof tmp) - len);
+ src = tmp;
+ len = 0;
+ }
+ y1 ^= br_dec64be(src);
+ y0 ^= br_dec64be(src + 8);
+
+ y0r = rev64(y0);
+ y1r = rev64(y1);
+ y2 = y0 ^ y1;
+ y2r = y0r ^ y1r;
+
+ z0 = bmul64(y0, h0);
+ z1 = bmul64(y1, h1);
+ z2 = bmul64(y2, h2);
+ z0h = bmul64(y0r, h0r);
+ z1h = bmul64(y1r, h1r);
+ z2h = bmul64(y2r, h2r);
+ z2 ^= z0 ^ z1;
+ z2h ^= z0h ^ z1h;
+ z0h = rev64(z0h) >> 1;
+ z1h = rev64(z1h) >> 1;
+ z2h = rev64(z2h) >> 1;
+
+ v0 = z0;
+ v1 = z0h ^ z2;
+ v2 = z1 ^ z2h;
+ v3 = z1h;
+
+ v3 = (v3 << 1) | (v2 >> 63);
+ v2 = (v2 << 1) | (v1 >> 63);
+ v1 = (v1 << 1) | (v0 >> 63);
+ v0 = (v0 << 1);
+
+ v2 ^= v0 ^ (v0 >> 1) ^ (v0 >> 2) ^ (v0 >> 7);
+ v1 ^= (v0 << 63) ^ (v0 << 62) ^ (v0 << 57);
+ v3 ^= v1 ^ (v1 >> 1) ^ (v1 >> 2) ^ (v1 >> 7);
+ v2 ^= (v1 << 63) ^ (v1 << 62) ^ (v1 << 57);
+
+ y0 = v2;
+ y1 = v3;
+ }
+
+ br_enc64be(yb, y1);
+ br_enc64be(yb + 8, y0);
+}
--- /dev/null
+/*
+ * 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"
+
+#define F(B, C, D) ((((C) ^ (D)) & (B)) ^ (D))
+#define G(B, C, D) ((((C) ^ (B)) & (D)) ^ (C))
+#define H(B, C, D) ((B) ^ (C) ^ (D))
+#define I(B, C, D) ((C) ^ ((B) | ~(D)))
+
+#define ROTL(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+
+/* see inner.h */
+const uint32_t br_md5_IV[4] = {
+ 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476
+};
+
+static const uint32_t K[64] = {
+ 0xD76AA478, 0xE8C7B756, 0x242070DB, 0xC1BDCEEE,
+ 0xF57C0FAF, 0x4787C62A, 0xA8304613, 0xFD469501,
+ 0x698098D8, 0x8B44F7AF, 0xFFFF5BB1, 0x895CD7BE,
+ 0x6B901122, 0xFD987193, 0xA679438E, 0x49B40821,
+
+ 0xF61E2562, 0xC040B340, 0x265E5A51, 0xE9B6C7AA,
+ 0xD62F105D, 0x02441453, 0xD8A1E681, 0xE7D3FBC8,
+ 0x21E1CDE6, 0xC33707D6, 0xF4D50D87, 0x455A14ED,
+ 0xA9E3E905, 0xFCEFA3F8, 0x676F02D9, 0x8D2A4C8A,
+
+ 0xFFFA3942, 0x8771F681, 0x6D9D6122, 0xFDE5380C,
+ 0xA4BEEA44, 0x4BDECFA9, 0xF6BB4B60, 0xBEBFBC70,
+ 0x289B7EC6, 0xEAA127FA, 0xD4EF3085, 0x04881D05,
+ 0xD9D4D039, 0xE6DB99E5, 0x1FA27CF8, 0xC4AC5665,
+
+ 0xF4292244, 0x432AFF97, 0xAB9423A7, 0xFC93A039,
+ 0x655B59C3, 0x8F0CCC92, 0xFFEFF47D, 0x85845DD1,
+ 0x6FA87E4F, 0xFE2CE6E0, 0xA3014314, 0x4E0811A1,
+ 0xF7537E82, 0xBD3AF235, 0x2AD7D2BB, 0xEB86D391
+};
+
+static const unsigned char MP[48] = {
+ 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12,
+ 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2,
+ 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9
+};
+
+/* see inner.h */
+void
+br_md5_round(const unsigned char *buf, uint32_t *val)
+{
+ uint32_t m[16];
+ uint32_t a, b, c, d;
+ int i;
+
+ a = val[0];
+ b = val[1];
+ c = val[2];
+ d = val[3];
+ /* obsolete
+ for (i = 0; i < 16; i ++) {
+ m[i] = br_dec32le(buf + (i << 2));
+ }
+ */
+ br_range_dec32le(m, 16, buf);
+
+ for (i = 0; i < 16; i += 4) {
+ a = b + ROTL(a + F(b, c, d) + m[i + 0] + K[i + 0], 7);
+ d = a + ROTL(d + F(a, b, c) + m[i + 1] + K[i + 1], 12);
+ c = d + ROTL(c + F(d, a, b) + m[i + 2] + K[i + 2], 17);
+ b = c + ROTL(b + F(c, d, a) + m[i + 3] + K[i + 3], 22);
+ }
+ for (i = 16; i < 32; i += 4) {
+ a = b + ROTL(a + G(b, c, d) + m[MP[i - 16]] + K[i + 0], 5);
+ d = a + ROTL(d + G(a, b, c) + m[MP[i - 15]] + K[i + 1], 9);
+ c = d + ROTL(c + G(d, a, b) + m[MP[i - 14]] + K[i + 2], 14);
+ b = c + ROTL(b + G(c, d, a) + m[MP[i - 13]] + K[i + 3], 20);
+ }
+ for (i = 32; i < 48; i += 4) {
+ a = b + ROTL(a + H(b, c, d) + m[MP[i - 16]] + K[i + 0], 4);
+ d = a + ROTL(d + H(a, b, c) + m[MP[i - 15]] + K[i + 1], 11);
+ c = d + ROTL(c + H(d, a, b) + m[MP[i - 14]] + K[i + 2], 16);
+ b = c + ROTL(b + H(c, d, a) + m[MP[i - 13]] + K[i + 3], 23);
+ }
+ for (i = 48; i < 64; i += 4) {
+ a = b + ROTL(a + I(b, c, d) + m[MP[i - 16]] + K[i + 0], 6);
+ d = a + ROTL(d + I(a, b, c) + m[MP[i - 15]] + K[i + 1], 10);
+ c = d + ROTL(c + I(d, a, b) + m[MP[i - 14]] + K[i + 2], 15);
+ b = c + ROTL(b + I(c, d, a) + m[MP[i - 13]] + K[i + 3], 21);
+ }
+
+ val[0] += a;
+ val[1] += b;
+ val[2] += c;
+ val[3] += d;
+}
+
+/* see bearssl.h */
+void
+br_md5_init(br_md5_context *cc)
+{
+ cc->vtable = &br_md5_vtable;
+ memcpy(cc->val, br_md5_IV, sizeof cc->val);
+ cc->count = 0;
+}
+
+/* see bearssl.h */
+void
+br_md5_update(br_md5_context *cc, const void *data, size_t len)
+{
+ const unsigned char *buf;
+ size_t ptr;
+
+ buf = data;
+ ptr = (size_t)cc->count & 63;
+ while (len > 0) {
+ size_t clen;
+
+ clen = 64 - ptr;
+ if (clen > len) {
+ clen = len;
+ }
+ memcpy(cc->buf + ptr, buf, clen);
+ ptr += clen;
+ buf += clen;
+ len -= clen;
+ cc->count += (uint64_t)clen;
+ if (ptr == 64) {
+ br_md5_round(cc->buf, cc->val);
+ ptr = 0;
+ }
+ }
+}
+
+/* see bearssl.h */
+void
+br_md5_out(const br_md5_context *cc, void *dst)
+{
+ unsigned char buf[64];
+ uint32_t val[4];
+ size_t ptr;
+
+ ptr = (size_t)cc->count & 63;
+ memcpy(buf, cc->buf, ptr);
+ memcpy(val, cc->val, sizeof val);
+ buf[ptr ++] = 0x80;
+ if (ptr > 56) {
+ memset(buf + ptr, 0, 64 - ptr);
+ br_md5_round(buf, val);
+ memset(buf, 0, 56);
+ } else {
+ memset(buf + ptr, 0, 56 - ptr);
+ }
+ br_enc64le(buf + 56, cc->count << 3);
+ br_md5_round(buf, val);
+ br_range_enc32le(dst, val, 4);
+}
+
+/* see bearssl.h */
+uint64_t
+br_md5_state(const br_md5_context *cc, void *dst)
+{
+ br_range_enc32le(dst, cc->val, 4);
+ return cc->count;
+}
+
+/* see bearssl.h */
+void
+br_md5_set_state(br_md5_context *cc, const void *stb, uint64_t count)
+{
+ br_range_dec32le(cc->val, 4, stb);
+ cc->count = count;
+}
+
+/* see bearssl.h */
+const br_hash_class br_md5_vtable = {
+ sizeof(br_md5_context),
+ BR_HASHDESC_ID(br_md5_ID)
+ | BR_HASHDESC_OUT(16)
+ | BR_HASHDESC_STATE(16)
+ | BR_HASHDESC_LBLEN(6)
+ | BR_HASHDESC_MD_PADDING,
+ (void (*)(const br_hash_class **))&br_md5_init,
+ (void (*)(const br_hash_class **, const void *, size_t))&br_md5_update,
+ (void (*)(const br_hash_class *const *, void *))&br_md5_out,
+ (uint64_t (*)(const br_hash_class *const *, void *))&br_md5_state,
+ (void (*)(const br_hash_class **, const void *, uint64_t))
+ &br_md5_set_state
+};
--- /dev/null
+/*
+ * 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.h */
+void
+br_md5sha1_init(br_md5sha1_context *cc)
+{
+ cc->vtable = &br_md5sha1_vtable;
+ memcpy(cc->val_md5, br_md5_IV, sizeof cc->val_md5);
+ memcpy(cc->val_sha1, br_sha1_IV, sizeof cc->val_sha1);
+ cc->count = 0;
+}
+
+/* see bearssl.h */
+void
+br_md5sha1_update(br_md5sha1_context *cc, const void *data, size_t len)
+{
+ const unsigned char *buf;
+ size_t ptr;
+
+ buf = data;
+ ptr = (size_t)cc->count & 63;
+ while (len > 0) {
+ size_t clen;
+
+ clen = 64 - ptr;
+ if (clen > len) {
+ clen = len;
+ }
+ memcpy(cc->buf + ptr, buf, clen);
+ ptr += clen;
+ buf += clen;
+ len -= clen;
+ cc->count += (uint64_t)clen;
+ if (ptr == 64) {
+ br_md5_round(cc->buf, cc->val_md5);
+ br_sha1_round(cc->buf, cc->val_sha1);
+ ptr = 0;
+ }
+ }
+}
+
+/* see bearssl.h */
+void
+br_md5sha1_out(const br_md5sha1_context *cc, void *dst)
+{
+ unsigned char buf[64];
+ uint32_t val_md5[4];
+ uint32_t val_sha1[5];
+ size_t ptr;
+ unsigned char *out;
+ uint64_t count;
+
+ count = cc->count;
+ ptr = (size_t)count & 63;
+ memcpy(buf, cc->buf, ptr);
+ memcpy(val_md5, cc->val_md5, sizeof val_md5);
+ memcpy(val_sha1, cc->val_sha1, sizeof val_sha1);
+ buf[ptr ++] = 0x80;
+ if (ptr > 56) {
+ memset(buf + ptr, 0, 64 - ptr);
+ br_md5_round(buf, val_md5);
+ br_sha1_round(buf, val_sha1);
+ memset(buf, 0, 56);
+ } else {
+ memset(buf + ptr, 0, 56 - ptr);
+ }
+ count <<= 3;
+ br_enc64le(buf + 56, count);
+ br_md5_round(buf, val_md5);
+ br_enc64be(buf + 56, count);
+ br_sha1_round(buf, val_sha1);
+ out = dst;
+ br_range_enc32le(out, val_md5, 4);
+ br_range_enc32be(out + 16, val_sha1, 5);
+}
+
+/* see bearssl.h */
+uint64_t
+br_md5sha1_state(const br_md5sha1_context *cc, void *dst)
+{
+ unsigned char *out;
+
+ out = dst;
+ br_range_enc32le(out, cc->val_md5, 4);
+ br_range_enc32be(out + 16, cc->val_sha1, 5);
+ return cc->count;
+}
+
+/* see bearssl.h */
+void
+br_md5sha1_set_state(br_md5sha1_context *cc, const void *stb, uint64_t count)
+{
+ const unsigned char *buf;
+
+ buf = stb;
+ br_range_dec32le(cc->val_md5, 4, buf);
+ br_range_dec32be(cc->val_sha1, 5, buf + 16);
+ cc->count = count;
+}
+
+/* see bearssl.h */
+const br_hash_class br_md5sha1_vtable = {
+ sizeof(br_md5sha1_context),
+ BR_HASHDESC_ID(br_md5sha1_ID)
+ | BR_HASHDESC_OUT(36)
+ | BR_HASHDESC_STATE(36)
+ | BR_HASHDESC_LBLEN(6),
+ (void (*)(const br_hash_class **))&br_md5sha1_init,
+ (void (*)(const br_hash_class **, const void *, size_t))
+ &br_md5sha1_update,
+ (void (*)(const br_hash_class *const *, void *))
+ &br_md5sha1_out,
+ (uint64_t (*)(const br_hash_class *const *, void *))
+ &br_md5sha1_state,
+ (void (*)(const br_hash_class **, const void *, uint64_t))
+ &br_md5sha1_set_state
+};
--- /dev/null
+/*
+ * 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"
+
+/*
+ * An aggregate context that is large enough for all supported hash
+ * functions.
+ */
+typedef union {
+ const br_hash_class *vtable;
+ br_md5_context md5;
+ br_sha1_context sha1;
+ br_sha224_context sha224;
+ br_sha256_context sha256;
+ br_sha384_context sha384;
+ br_sha512_context sha512;
+} gen_hash_context;
+
+/*
+ * Get the offset to the state for a specific hash function within the
+ * context structure. This shall be called only for the supported hash
+ * functions,
+ */
+static size_t
+get_state_offset(int id)
+{
+ if (id >= 5) {
+ /*
+ * SHA-384 has id 5, and SHA-512 has id 6. Both use
+ * eight 64-bit words for their state.
+ */
+ return offsetof(br_multihash_context, val_64)
+ + ((size_t)(id - 5) * (8 * sizeof(uint64_t)));
+ } else {
+ /*
+ * MD5 has id 1, SHA-1 has id 2, SHA-224 has id 3 and
+ * SHA-256 has id 4. They use 32-bit words for their
+ * states (4 words for MD5, 5 for SHA-1, 8 for SHA-224
+ * and 8 for SHA-256).
+ */
+ unsigned x;
+
+ x = id - 1;
+ x = ((x + (x & (x >> 1))) << 2) + (x >> 1);
+ return offsetof(br_multihash_context, val_32)
+ + x * sizeof(uint32_t);
+ }
+}
+
+/* see bearssl_hash.h */
+void
+br_multihash_zero(br_multihash_context *ctx)
+{
+ /*
+ * This is not standard, but yields very short and efficient code,
+ * and it works "everywhere".
+ */
+ memset(ctx, 0, sizeof *ctx);
+}
+
+/* see bearssl_hash.h */
+void
+br_multihash_init(br_multihash_context *ctx)
+{
+ int i;
+
+ ctx->count = 0;
+ for (i = 1; i <= 6; i ++) {
+ const br_hash_class *hc;
+
+ hc = ctx->impl[i - 1];
+ if (hc != NULL) {
+ gen_hash_context g;
+
+ hc->init(&g.vtable);
+ hc->state(&g.vtable,
+ (unsigned char *)ctx + get_state_offset(i));
+ }
+ }
+}
+
+/* see bearssl_hash.h */
+void
+br_multihash_update(br_multihash_context *ctx, const void *data, size_t len)
+{
+ const unsigned char *buf;
+ size_t ptr;
+
+ buf = data;
+ ptr = (size_t)ctx->count & 127;
+ while (len > 0) {
+ size_t clen;
+
+ clen = 128 - ptr;
+ if (clen > len) {
+ clen = len;
+ }
+ memcpy(ctx->buf + ptr, buf, clen);
+ ptr += clen;
+ buf += clen;
+ len -= clen;
+ ctx->count += (uint64_t)clen;
+ if (ptr == 128) {
+ int i;
+
+ for (i = 1; i <= 6; i ++) {
+ const br_hash_class *hc;
+
+ hc = ctx->impl[i - 1];
+ if (hc != NULL) {
+ gen_hash_context g;
+ unsigned char *state;
+
+ state = (unsigned char *)ctx
+ + get_state_offset(i);
+ hc->set_state(&g.vtable,
+ state, ctx->count - 128);
+ hc->update(&g.vtable, ctx->buf, 128);
+ hc->state(&g.vtable, state);
+ }
+ }
+ ptr = 0;
+ }
+ }
+}
+
+/* see bearssl_hash.h */
+size_t
+br_multihash_out(const br_multihash_context *ctx, int id, void *dst)
+{
+ const br_hash_class *hc;
+ gen_hash_context g;
+ const unsigned char *state;
+
+ hc = ctx->impl[id - 1];
+ if (hc == NULL) {
+ return 0;
+ }
+ state = (const unsigned char *)ctx + get_state_offset(id);
+ hc->set_state(&g.vtable, state, ctx->count & ~(uint64_t)127);
+ hc->update(&g.vtable, ctx->buf, ctx->count & (uint64_t)127);
+ hc->out(&g.vtable, dst);
+ return (hc->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK;
+}
--- /dev/null
+/*
+ * 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"
+
+#define F(B, C, D) ((((C) ^ (D)) & (B)) ^ (D))
+#define G(B, C, D) ((B) ^ (C) ^ (D))
+#define H(B, C, D) (((D) & (C)) | (((D) | (C)) & (B)))
+#define I(B, C, D) G(B, C, D)
+
+#define ROTL(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+
+#define K1 ((uint32_t)0x5A827999)
+#define K2 ((uint32_t)0x6ED9EBA1)
+#define K3 ((uint32_t)0x8F1BBCDC)
+#define K4 ((uint32_t)0xCA62C1D6)
+
+/* see inner.h */
+const uint32_t br_sha1_IV[5] = {
+ 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0
+};
+
+/* see inner.h */
+void
+br_sha1_round(const unsigned char *buf, uint32_t *val)
+{
+ uint32_t m[80];
+ uint32_t a, b, c, d, e;
+ int i;
+
+ a = val[0];
+ b = val[1];
+ c = val[2];
+ d = val[3];
+ e = val[4];
+ br_range_dec32be(m, 16, buf);
+ for (i = 16; i < 80; i ++) {
+ uint32_t x = m[i - 3] ^ m[i - 8] ^ m[i - 14] ^ m[i - 16];
+ m[i] = ROTL(x, 1);
+ }
+
+ for (i = 0; i < 20; i += 5) {
+ e += ROTL(a, 5) + F(b, c, d) + K1 + m[i + 0]; b = ROTL(b, 30);
+ d += ROTL(e, 5) + F(a, b, c) + K1 + m[i + 1]; a = ROTL(a, 30);
+ c += ROTL(d, 5) + F(e, a, b) + K1 + m[i + 2]; e = ROTL(e, 30);
+ b += ROTL(c, 5) + F(d, e, a) + K1 + m[i + 3]; d = ROTL(d, 30);
+ a += ROTL(b, 5) + F(c, d, e) + K1 + m[i + 4]; c = ROTL(c, 30);
+ }
+ for (i = 20; i < 40; i += 5) {
+ e += ROTL(a, 5) + G(b, c, d) + K2 + m[i + 0]; b = ROTL(b, 30);
+ d += ROTL(e, 5) + G(a, b, c) + K2 + m[i + 1]; a = ROTL(a, 30);
+ c += ROTL(d, 5) + G(e, a, b) + K2 + m[i + 2]; e = ROTL(e, 30);
+ b += ROTL(c, 5) + G(d, e, a) + K2 + m[i + 3]; d = ROTL(d, 30);
+ a += ROTL(b, 5) + G(c, d, e) + K2 + m[i + 4]; c = ROTL(c, 30);
+ }
+ for (i = 40; i < 60; i += 5) {
+ e += ROTL(a, 5) + H(b, c, d) + K3 + m[i + 0]; b = ROTL(b, 30);
+ d += ROTL(e, 5) + H(a, b, c) + K3 + m[i + 1]; a = ROTL(a, 30);
+ c += ROTL(d, 5) + H(e, a, b) + K3 + m[i + 2]; e = ROTL(e, 30);
+ b += ROTL(c, 5) + H(d, e, a) + K3 + m[i + 3]; d = ROTL(d, 30);
+ a += ROTL(b, 5) + H(c, d, e) + K3 + m[i + 4]; c = ROTL(c, 30);
+ }
+ for (i = 60; i < 80; i += 5) {
+ e += ROTL(a, 5) + I(b, c, d) + K4 + m[i + 0]; b = ROTL(b, 30);
+ d += ROTL(e, 5) + I(a, b, c) + K4 + m[i + 1]; a = ROTL(a, 30);
+ c += ROTL(d, 5) + I(e, a, b) + K4 + m[i + 2]; e = ROTL(e, 30);
+ b += ROTL(c, 5) + I(d, e, a) + K4 + m[i + 3]; d = ROTL(d, 30);
+ a += ROTL(b, 5) + I(c, d, e) + K4 + m[i + 4]; c = ROTL(c, 30);
+ }
+
+ val[0] += a;
+ val[1] += b;
+ val[2] += c;
+ val[3] += d;
+ val[4] += e;
+}
+
+/* see bearssl.h */
+void
+br_sha1_init(br_sha1_context *cc)
+{
+ cc->vtable = &br_sha1_vtable;
+ memcpy(cc->val, br_sha1_IV, sizeof cc->val);
+ cc->count = 0;
+}
+
+/* see bearssl.h */
+void
+br_sha1_update(br_sha1_context *cc, const void *data, size_t len)
+{
+ const unsigned char *buf;
+ size_t ptr;
+
+ buf = data;
+ ptr = (size_t)cc->count & 63;
+ while (len > 0) {
+ size_t clen;
+
+ clen = 64 - ptr;
+ if (clen > len) {
+ clen = len;
+ }
+ memcpy(cc->buf + ptr, buf, clen);
+ ptr += clen;
+ buf += clen;
+ len -= clen;
+ cc->count += (uint64_t)clen;
+ if (ptr == 64) {
+ br_sha1_round(cc->buf, cc->val);
+ ptr = 0;
+ }
+ }
+}
+
+/* see bearssl.h */
+void
+br_sha1_out(const br_sha1_context *cc, void *dst)
+{
+ unsigned char buf[64];
+ uint32_t val[5];
+ size_t ptr;
+
+ ptr = (size_t)cc->count & 63;
+ memcpy(buf, cc->buf, ptr);
+ memcpy(val, cc->val, sizeof val);
+ buf[ptr ++] = 0x80;
+ if (ptr > 56) {
+ memset(buf + ptr, 0, 64 - ptr);
+ br_sha1_round(buf, val);
+ memset(buf, 0, 56);
+ } else {
+ memset(buf + ptr, 0, 56 - ptr);
+ }
+ br_enc64be(buf + 56, cc->count << 3);
+ br_sha1_round(buf, val);
+ br_range_enc32be(dst, val, 5);
+}
+
+/* see bearssl.h */
+uint64_t
+br_sha1_state(const br_sha1_context *cc, void *dst)
+{
+ br_range_enc32be(dst, cc->val, 5);
+ return cc->count;
+}
+
+/* see bearssl.h */
+void
+br_sha1_set_state(br_sha1_context *cc, const void *stb, uint64_t count)
+{
+ br_range_dec32be(cc->val, 5, stb);
+ cc->count = count;
+}
+
+/* see bearssl.h */
+const br_hash_class br_sha1_vtable = {
+ sizeof(br_sha1_context),
+ BR_HASHDESC_ID(br_sha1_ID)
+ | BR_HASHDESC_OUT(20)
+ | BR_HASHDESC_STATE(20)
+ | BR_HASHDESC_LBLEN(6)
+ | BR_HASHDESC_MD_PADDING
+ | BR_HASHDESC_MD_PADDING_BE,
+ (void (*)(const br_hash_class **))&br_sha1_init,
+ (void (*)(const br_hash_class **, const void *, size_t))&br_sha1_update,
+ (void (*)(const br_hash_class *const *, void *))&br_sha1_out,
+ (uint64_t (*)(const br_hash_class *const *, void *))&br_sha1_state,
+ (void (*)(const br_hash_class **, const void *, uint64_t))
+ &br_sha1_set_state
+};
--- /dev/null
+/*
+ * 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"
+
+#define CH(X, Y, Z) ((((Y) ^ (Z)) & (X)) ^ (Z))
+#define MAJ(X, Y, Z) (((Y) & (Z)) | (((Y) | (Z)) & (X)))
+
+#define ROTR(x, n) (((uint64_t)(x) << (64 - (n))) | ((uint64_t)(x) >> (n)))
+
+#define BSG5_0(x) (ROTR(x, 28) ^ ROTR(x, 34) ^ ROTR(x, 39))
+#define BSG5_1(x) (ROTR(x, 14) ^ ROTR(x, 18) ^ ROTR(x, 41))
+#define SSG5_0(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ (uint64_t)((x) >> 7))
+#define SSG5_1(x) (ROTR(x, 19) ^ ROTR(x, 61) ^ (uint64_t)((x) >> 6))
+
+static const uint64_t IV384[8] = {
+ 0xCBBB9D5DC1059ED8, 0x629A292A367CD507,
+ 0x9159015A3070DD17, 0x152FECD8F70E5939,
+ 0x67332667FFC00B31, 0x8EB44A8768581511,
+ 0xDB0C2E0D64F98FA7, 0x47B5481DBEFA4FA4
+};
+
+static const uint64_t IV512[8] = {
+ 0x6A09E667F3BCC908, 0xBB67AE8584CAA73B,
+ 0x3C6EF372FE94F82B, 0xA54FF53A5F1D36F1,
+ 0x510E527FADE682D1, 0x9B05688C2B3E6C1F,
+ 0x1F83D9ABFB41BD6B, 0x5BE0CD19137E2179
+};
+
+static const uint64_t K[80] = {
+ 0x428A2F98D728AE22, 0x7137449123EF65CD,
+ 0xB5C0FBCFEC4D3B2F, 0xE9B5DBA58189DBBC,
+ 0x3956C25BF348B538, 0x59F111F1B605D019,
+ 0x923F82A4AF194F9B, 0xAB1C5ED5DA6D8118,
+ 0xD807AA98A3030242, 0x12835B0145706FBE,
+ 0x243185BE4EE4B28C, 0x550C7DC3D5FFB4E2,
+ 0x72BE5D74F27B896F, 0x80DEB1FE3B1696B1,
+ 0x9BDC06A725C71235, 0xC19BF174CF692694,
+ 0xE49B69C19EF14AD2, 0xEFBE4786384F25E3,
+ 0x0FC19DC68B8CD5B5, 0x240CA1CC77AC9C65,
+ 0x2DE92C6F592B0275, 0x4A7484AA6EA6E483,
+ 0x5CB0A9DCBD41FBD4, 0x76F988DA831153B5,
+ 0x983E5152EE66DFAB, 0xA831C66D2DB43210,
+ 0xB00327C898FB213F, 0xBF597FC7BEEF0EE4,
+ 0xC6E00BF33DA88FC2, 0xD5A79147930AA725,
+ 0x06CA6351E003826F, 0x142929670A0E6E70,
+ 0x27B70A8546D22FFC, 0x2E1B21385C26C926,
+ 0x4D2C6DFC5AC42AED, 0x53380D139D95B3DF,
+ 0x650A73548BAF63DE, 0x766A0ABB3C77B2A8,
+ 0x81C2C92E47EDAEE6, 0x92722C851482353B,
+ 0xA2BFE8A14CF10364, 0xA81A664BBC423001,
+ 0xC24B8B70D0F89791, 0xC76C51A30654BE30,
+ 0xD192E819D6EF5218, 0xD69906245565A910,
+ 0xF40E35855771202A, 0x106AA07032BBD1B8,
+ 0x19A4C116B8D2D0C8, 0x1E376C085141AB53,
+ 0x2748774CDF8EEB99, 0x34B0BCB5E19B48A8,
+ 0x391C0CB3C5C95A63, 0x4ED8AA4AE3418ACB,
+ 0x5B9CCA4F7763E373, 0x682E6FF3D6B2B8A3,
+ 0x748F82EE5DEFB2FC, 0x78A5636F43172F60,
+ 0x84C87814A1F0AB72, 0x8CC702081A6439EC,
+ 0x90BEFFFA23631E28, 0xA4506CEBDE82BDE9,
+ 0xBEF9A3F7B2C67915, 0xC67178F2E372532B,
+ 0xCA273ECEEA26619C, 0xD186B8C721C0C207,
+ 0xEADA7DD6CDE0EB1E, 0xF57D4F7FEE6ED178,
+ 0x06F067AA72176FBA, 0x0A637DC5A2C898A6,
+ 0x113F9804BEF90DAE, 0x1B710B35131C471B,
+ 0x28DB77F523047D84, 0x32CAAB7B40C72493,
+ 0x3C9EBE0A15C9BEBC, 0x431D67C49C100D4C,
+ 0x4CC5D4BECB3E42B6, 0x597F299CFC657E2A,
+ 0x5FCB6FAB3AD6FAEC, 0x6C44198C4A475817
+};
+
+static void
+sha2big_round(const unsigned char *buf, uint64_t *val)
+{
+
+#define SHA2BIG_STEP(A, B, C, D, E, F, G, H, j) do { \
+ uint64_t T1, T2; \
+ T1 = H + BSG5_1(E) + CH(E, F, G) + K[j] + w[j]; \
+ T2 = BSG5_0(A) + MAJ(A, B, C); \
+ D += T1; \
+ H = T1 + T2; \
+ } while (0)
+
+ int i;
+ uint64_t a, b, c, d, e, f, g, h;
+ uint64_t w[80];
+
+ br_range_dec64be(w, 16, buf);
+ for (i = 16; i < 80; i ++) {
+ w[i] = SSG5_1(w[i - 2]) + w[i - 7]
+ + SSG5_0(w[i - 15]) + w[i - 16];
+ }
+ a = val[0];
+ b = val[1];
+ c = val[2];
+ d = val[3];
+ e = val[4];
+ f = val[5];
+ g = val[6];
+ h = val[7];
+ for (i = 0; i < 80; i += 8) {
+ SHA2BIG_STEP(a, b, c, d, e, f, g, h, i + 0);
+ SHA2BIG_STEP(h, a, b, c, d, e, f, g, i + 1);
+ SHA2BIG_STEP(g, h, a, b, c, d, e, f, i + 2);
+ SHA2BIG_STEP(f, g, h, a, b, c, d, e, i + 3);
+ SHA2BIG_STEP(e, f, g, h, a, b, c, d, i + 4);
+ SHA2BIG_STEP(d, e, f, g, h, a, b, c, i + 5);
+ SHA2BIG_STEP(c, d, e, f, g, h, a, b, i + 6);
+ SHA2BIG_STEP(b, c, d, e, f, g, h, a, i + 7);
+ }
+ val[0] += a;
+ val[1] += b;
+ val[2] += c;
+ val[3] += d;
+ val[4] += e;
+ val[5] += f;
+ val[6] += g;
+ val[7] += h;
+}
+
+static void
+sha2big_update(br_sha384_context *cc, const void *data, size_t len)
+{
+ const unsigned char *buf;
+ size_t ptr;
+
+ buf = data;
+ ptr = (size_t)cc->count & 127;
+ cc->count += (uint64_t)len;
+ while (len > 0) {
+ size_t clen;
+
+ clen = 128 - ptr;
+ if (clen > len) {
+ clen = len;
+ }
+ memcpy(cc->buf + ptr, buf, clen);
+ ptr += clen;
+ buf += clen;
+ len -= clen;
+ if (ptr == 128) {
+ sha2big_round(cc->buf, cc->val);
+ ptr = 0;
+ }
+ }
+}
+
+static void
+sha2big_out(const br_sha384_context *cc, void *dst, int num)
+{
+ unsigned char buf[128];
+ uint64_t val[8];
+ size_t ptr;
+
+ ptr = (size_t)cc->count & 127;
+ memcpy(buf, cc->buf, ptr);
+ memcpy(val, cc->val, sizeof val);
+ buf[ptr ++] = 0x80;
+ if (ptr > 112) {
+ memset(buf + ptr, 0, 128 - ptr);
+ sha2big_round(buf, val);
+ memset(buf, 0, 112);
+ } else {
+ memset(buf + ptr, 0, 112 - ptr);
+ }
+ br_enc64be(buf + 112, cc->count >> 61);
+ br_enc64be(buf + 120, cc->count << 3);
+ sha2big_round(buf, val);
+ br_range_enc64be(dst, val, num);
+}
+
+/* see bearssl.h */
+void
+br_sha384_init(br_sha384_context *cc)
+{
+ cc->vtable = &br_sha384_vtable;
+ memcpy(cc->val, IV384, sizeof IV384);
+ cc->count = 0;
+}
+
+/* see bearssl.h */
+void
+br_sha384_update(br_sha384_context *cc, const void *data, size_t len)
+{
+ sha2big_update(cc, data, len);
+}
+
+/* see bearssl.h */
+void
+br_sha384_out(const br_sha384_context *cc, void *dst)
+{
+ sha2big_out(cc, dst, 6);
+}
+
+/* see bearssl.h */
+uint64_t
+br_sha384_state(const br_sha384_context *cc, void *dst)
+{
+ br_range_enc64be(dst, cc->val, 8);
+ return cc->count;
+}
+
+/* see bearssl.h */
+void
+br_sha384_set_state(br_sha384_context *cc, const void *stb, uint64_t count)
+{
+ br_range_dec64be(cc->val, 8, stb);
+ cc->count = count;
+}
+
+/* see bearssl.h */
+void
+br_sha512_init(br_sha512_context *cc)
+{
+ cc->vtable = &br_sha512_vtable;
+ memcpy(cc->val, IV512, sizeof IV512);
+ cc->count = 0;
+}
+
+/* see bearssl.h */
+void
+br_sha512_out(const br_sha512_context *cc, void *dst)
+{
+ sha2big_out(cc, dst, 8);
+}
+
+/* see bearssl.h */
+const br_hash_class br_sha384_vtable = {
+ sizeof(br_sha384_context),
+ BR_HASHDESC_ID(br_sha384_ID)
+ | BR_HASHDESC_OUT(48)
+ | BR_HASHDESC_STATE(64)
+ | BR_HASHDESC_LBLEN(7)
+ | BR_HASHDESC_MD_PADDING
+ | BR_HASHDESC_MD_PADDING_BE
+ | BR_HASHDESC_MD_PADDING_128,
+ (void (*)(const br_hash_class **))&br_sha384_init,
+ (void (*)(const br_hash_class **, const void *, size_t))
+ &br_sha384_update,
+ (void (*)(const br_hash_class *const *, void *))&br_sha384_out,
+ (uint64_t (*)(const br_hash_class *const *, void *))&br_sha384_state,
+ (void (*)(const br_hash_class **, const void *, uint64_t))
+ &br_sha384_set_state
+};
+
+/* see bearssl.h */
+const br_hash_class br_sha512_vtable = {
+ sizeof(br_sha512_context),
+ BR_HASHDESC_ID(br_sha512_ID)
+ | BR_HASHDESC_OUT(64)
+ | BR_HASHDESC_STATE(64)
+ | BR_HASHDESC_LBLEN(7)
+ | BR_HASHDESC_MD_PADDING
+ | BR_HASHDESC_MD_PADDING_BE
+ | BR_HASHDESC_MD_PADDING_128,
+ (void (*)(const br_hash_class **))&br_sha512_init,
+ (void (*)(const br_hash_class **, const void *, size_t))
+ &br_sha512_update,
+ (void (*)(const br_hash_class *const *, void *))&br_sha512_out,
+ (uint64_t (*)(const br_hash_class *const *, void *))&br_sha512_state,
+ (void (*)(const br_hash_class **, const void *, uint64_t))
+ &br_sha512_set_state
+};
--- /dev/null
+/*
+ * 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"
+
+#define CH(X, Y, Z) ((((Y) ^ (Z)) & (X)) ^ (Z))
+#define MAJ(X, Y, Z) (((Y) & (Z)) | (((Y) | (Z)) & (X)))
+
+#define ROTR(x, n) (((uint32_t)(x) << (32 - (n))) | ((uint32_t)(x) >> (n)))
+
+#define BSG2_0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
+#define BSG2_1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
+#define SSG2_0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ (uint32_t)((x) >> 3))
+#define SSG2_1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ (uint32_t)((x) >> 10))
+
+/* see inner.h */
+const uint32_t br_sha224_IV[8] = {
+ 0xC1059ED8, 0x367CD507, 0x3070DD17, 0xF70E5939,
+ 0xFFC00B31, 0x68581511, 0x64F98FA7, 0xBEFA4FA4
+};
+
+/* see inner.h */
+const uint32_t br_sha256_IV[8] = {
+ 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
+ 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19
+};
+
+static const uint32_t K[64] = {
+ 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5,
+ 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5,
+ 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3,
+ 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174,
+ 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC,
+ 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA,
+ 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7,
+ 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967,
+ 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13,
+ 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85,
+ 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3,
+ 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070,
+ 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5,
+ 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3,
+ 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208,
+ 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2
+};
+
+/* see inner.h */
+void
+br_sha2small_round(const unsigned char *buf, uint32_t *val)
+{
+
+#define SHA2_STEP(A, B, C, D, E, F, G, H, j) do { \
+ uint32_t T1, T2; \
+ T1 = H + BSG2_1(E) + CH(E, F, G) + K[j] + w[j]; \
+ T2 = BSG2_0(A) + MAJ(A, B, C); \
+ D += T1; \
+ H = T1 + T2; \
+ } while (0)
+
+ int i;
+ uint32_t a, b, c, d, e, f, g, h;
+ uint32_t w[64];
+
+ br_range_dec32be(w, 16, buf);
+ for (i = 16; i < 64; i ++) {
+ w[i] = SSG2_1(w[i - 2]) + w[i - 7]
+ + SSG2_0(w[i - 15]) + w[i - 16];
+ }
+ a = val[0];
+ b = val[1];
+ c = val[2];
+ d = val[3];
+ e = val[4];
+ f = val[5];
+ g = val[6];
+ h = val[7];
+ for (i = 0; i < 64; i += 8) {
+ SHA2_STEP(a, b, c, d, e, f, g, h, i + 0);
+ SHA2_STEP(h, a, b, c, d, e, f, g, i + 1);
+ SHA2_STEP(g, h, a, b, c, d, e, f, i + 2);
+ SHA2_STEP(f, g, h, a, b, c, d, e, i + 3);
+ SHA2_STEP(e, f, g, h, a, b, c, d, i + 4);
+ SHA2_STEP(d, e, f, g, h, a, b, c, i + 5);
+ SHA2_STEP(c, d, e, f, g, h, a, b, i + 6);
+ SHA2_STEP(b, c, d, e, f, g, h, a, i + 7);
+ }
+ val[0] += a;
+ val[1] += b;
+ val[2] += c;
+ val[3] += d;
+ val[4] += e;
+ val[5] += f;
+ val[6] += g;
+ val[7] += h;
+
+#if 0
+/* obsolete */
+#define SHA2_MEXP1(pc) do { \
+ W[pc] = br_dec32be(buf + ((pc) << 2)); \
+ } while (0)
+
+#define SHA2_MEXP2(pc) do { \
+ W[(pc) & 0x0F] = SSG2_1(W[((pc) - 2) & 0x0F]) \
+ + W[((pc) - 7) & 0x0F] \
+ + SSG2_0(W[((pc) - 15) & 0x0F]) + W[(pc) & 0x0F]; \
+ } while (0)
+
+#define SHA2_STEPn(n, a, b, c, d, e, f, g, h, pc) do { \
+ uint32_t t1, t2; \
+ SHA2_MEXP ## n(pc); \
+ t1 = h + BSG2_1(e) + CH(e, f, g) \
+ + K[pcount + (pc)] + W[(pc) & 0x0F]; \
+ t2 = BSG2_0(a) + MAJ(a, b, c); \
+ d += t1; \
+ h = t1 + t2; \
+ } while (0)
+
+#define SHA2_STEP1(a, b, c, d, e, f, g, h, pc) \
+ SHA2_STEPn(1, a, b, c, d, e, f, g, h, pc)
+#define SHA2_STEP2(a, b, c, d, e, f, g, h, pc) \
+ SHA2_STEPn(2, a, b, c, d, e, f, g, h, pc)
+
+ uint32_t A, B, C, D, E, F, G, H;
+ uint32_t W[16];
+ unsigned pcount;
+
+ A = val[0];
+ B = val[1];
+ C = val[2];
+ D = val[3];
+ E = val[4];
+ F = val[5];
+ G = val[6];
+ H = val[7];
+ pcount = 0;
+ SHA2_STEP1(A, B, C, D, E, F, G, H, 0);
+ SHA2_STEP1(H, A, B, C, D, E, F, G, 1);
+ SHA2_STEP1(G, H, A, B, C, D, E, F, 2);
+ SHA2_STEP1(F, G, H, A, B, C, D, E, 3);
+ SHA2_STEP1(E, F, G, H, A, B, C, D, 4);
+ SHA2_STEP1(D, E, F, G, H, A, B, C, 5);
+ SHA2_STEP1(C, D, E, F, G, H, A, B, 6);
+ SHA2_STEP1(B, C, D, E, F, G, H, A, 7);
+ SHA2_STEP1(A, B, C, D, E, F, G, H, 8);
+ SHA2_STEP1(H, A, B, C, D, E, F, G, 9);
+ SHA2_STEP1(G, H, A, B, C, D, E, F, 10);
+ SHA2_STEP1(F, G, H, A, B, C, D, E, 11);
+ SHA2_STEP1(E, F, G, H, A, B, C, D, 12);
+ SHA2_STEP1(D, E, F, G, H, A, B, C, 13);
+ SHA2_STEP1(C, D, E, F, G, H, A, B, 14);
+ SHA2_STEP1(B, C, D, E, F, G, H, A, 15);
+ for (pcount = 16; pcount < 64; pcount += 16) {
+ SHA2_STEP2(A, B, C, D, E, F, G, H, 0);
+ SHA2_STEP2(H, A, B, C, D, E, F, G, 1);
+ SHA2_STEP2(G, H, A, B, C, D, E, F, 2);
+ SHA2_STEP2(F, G, H, A, B, C, D, E, 3);
+ SHA2_STEP2(E, F, G, H, A, B, C, D, 4);
+ SHA2_STEP2(D, E, F, G, H, A, B, C, 5);
+ SHA2_STEP2(C, D, E, F, G, H, A, B, 6);
+ SHA2_STEP2(B, C, D, E, F, G, H, A, 7);
+ SHA2_STEP2(A, B, C, D, E, F, G, H, 8);
+ SHA2_STEP2(H, A, B, C, D, E, F, G, 9);
+ SHA2_STEP2(G, H, A, B, C, D, E, F, 10);
+ SHA2_STEP2(F, G, H, A, B, C, D, E, 11);
+ SHA2_STEP2(E, F, G, H, A, B, C, D, 12);
+ SHA2_STEP2(D, E, F, G, H, A, B, C, 13);
+ SHA2_STEP2(C, D, E, F, G, H, A, B, 14);
+ SHA2_STEP2(B, C, D, E, F, G, H, A, 15);
+ }
+ val[0] += A;
+ val[1] += B;
+ val[2] += C;
+ val[3] += D;
+ val[4] += E;
+ val[5] += F;
+ val[6] += G;
+ val[7] += H;
+#endif
+}
+
+static void
+sha2small_update(br_sha224_context *cc, const void *data, size_t len)
+{
+ const unsigned char *buf;
+ size_t ptr;
+
+ buf = data;
+ ptr = (size_t)cc->count & 63;
+ cc->count += (uint64_t)len;
+ while (len > 0) {
+ size_t clen;
+
+ clen = 64 - ptr;
+ if (clen > len) {
+ clen = len;
+ }
+ memcpy(cc->buf + ptr, buf, clen);
+ ptr += clen;
+ buf += clen;
+ len -= clen;
+ if (ptr == 64) {
+ br_sha2small_round(cc->buf, cc->val);
+ ptr = 0;
+ }
+ }
+}
+
+static void
+sha2small_out(const br_sha224_context *cc, void *dst, int num)
+{
+ unsigned char buf[64];
+ uint32_t val[8];
+ size_t ptr;
+
+ ptr = (size_t)cc->count & 63;
+ memcpy(buf, cc->buf, ptr);
+ memcpy(val, cc->val, sizeof val);
+ buf[ptr ++] = 0x80;
+ if (ptr > 56) {
+ memset(buf + ptr, 0, 64 - ptr);
+ br_sha2small_round(buf, val);
+ memset(buf, 0, 56);
+ } else {
+ memset(buf + ptr, 0, 56 - ptr);
+ }
+ br_enc64be(buf + 56, cc->count << 3);
+ br_sha2small_round(buf, val);
+ br_range_enc32be(dst, val, num);
+}
+
+/* see bearssl.h */
+void
+br_sha224_init(br_sha224_context *cc)
+{
+ cc->vtable = &br_sha224_vtable;
+ memcpy(cc->val, br_sha224_IV, sizeof cc->val);
+ cc->count = 0;
+}
+
+/* see bearssl.h */
+void
+br_sha224_update(br_sha224_context *cc, const void *data, size_t len)
+{
+ sha2small_update(cc, data, len);
+}
+
+/* see bearssl.h */
+void
+br_sha224_out(const br_sha224_context *cc, void *dst)
+{
+ sha2small_out(cc, dst, 7);
+}
+
+/* see bearssl.h */
+uint64_t
+br_sha224_state(const br_sha224_context *cc, void *dst)
+{
+ br_range_enc32be(dst, cc->val, 8);
+ return cc->count;
+}
+
+/* see bearssl.h */
+void
+br_sha224_set_state(br_sha224_context *cc, const void *stb, uint64_t count)
+{
+ br_range_dec32be(cc->val, 8, stb);
+ cc->count = count;
+}
+
+/* see bearssl.h */
+void
+br_sha256_init(br_sha256_context *cc)
+{
+ cc->vtable = &br_sha256_vtable;
+ memcpy(cc->val, br_sha256_IV, sizeof cc->val);
+ cc->count = 0;
+}
+
+/* see bearssl.h */
+void
+br_sha256_out(const br_sha256_context *cc, void *dst)
+{
+ sha2small_out(cc, dst, 8);
+}
+
+/* see bearssl.h */
+const br_hash_class br_sha224_vtable = {
+ sizeof(br_sha224_context),
+ BR_HASHDESC_ID(br_sha224_ID)
+ | BR_HASHDESC_OUT(28)
+ | BR_HASHDESC_STATE(32)
+ | BR_HASHDESC_LBLEN(6)
+ | BR_HASHDESC_MD_PADDING
+ | BR_HASHDESC_MD_PADDING_BE,
+ (void (*)(const br_hash_class **))&br_sha224_init,
+ (void (*)(const br_hash_class **,
+ const void *, size_t))&br_sha224_update,
+ (void (*)(const br_hash_class *const *, void *))&br_sha224_out,
+ (uint64_t (*)(const br_hash_class *const *, void *))&br_sha224_state,
+ (void (*)(const br_hash_class **, const void *, uint64_t))
+ &br_sha224_set_state
+};
+
+/* see bearssl.h */
+const br_hash_class br_sha256_vtable = {
+ sizeof(br_sha256_context),
+ BR_HASHDESC_ID(br_sha256_ID)
+ | BR_HASHDESC_OUT(32)
+ | BR_HASHDESC_STATE(32)
+ | BR_HASHDESC_LBLEN(6)
+ | BR_HASHDESC_MD_PADDING
+ | BR_HASHDESC_MD_PADDING_BE,
+ (void (*)(const br_hash_class **))&br_sha256_init,
+ (void (*)(const br_hash_class **,
+ const void *, size_t))&br_sha256_update,
+ (void (*)(const br_hash_class *const *, void *))&br_sha256_out,
+ (uint64_t (*)(const br_hash_class *const *, void *))&br_sha256_state,
+ (void (*)(const br_hash_class **, const void *, uint64_t))
+ &br_sha256_set_state
+};
--- /dev/null
+/*
+ * 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.
+ */
+
+#ifndef INNER_H__
+#define INNER_H__
+
+#include <string.h>
+#include <limits.h>
+
+#include "config.h"
+#include "bearssl.h"
+
+/*
+ * Maximum size for a RSA modulus (in bits). Allocated stack buffers
+ * depend on that size, so this value should be kept small. Currently,
+ * 2048-bit RSA keys offer adequate security, and should still do so for
+ * the next few decades; however, a number of widespread PKI have
+ * already set their root keys to RSA-4096, so we should be able to
+ * process such keys.
+ *
+ * This value MUST be a multiple of 64.
+ */
+#define BR_MAX_RSA_SIZE 4096
+
+/*
+ * Maximum size for a RSA factor (in bits). This is for RSA private-key
+ * operations. Default is to support factors up to a bit more than half
+ * the maximum modulus size.
+ *
+ * This value MUST be a multiple of 32.
+ */
+#define BR_MAX_RSA_FACTOR ((BR_MAX_RSA_SIZE + 64) >> 1)
+
+/*
+ * Maximum size for an EC curve (modulus or order), in bits. Size of
+ * stack buffers depends on that parameter. This size MUST be a multiple
+ * of 8 (so that decoding an integer with that many bytes does not
+ * overflow).
+ */
+#define BR_MAX_EC_SIZE 528
+
+/*
+ * Some macros to recognize the current architecture. Right now, we are
+ * interested into automatically recognizing architecture with efficient
+ * 64-bit types so that we may automatically use implementations that
+ * use 64-bit registers in that case. Future versions may detect, e.g.,
+ * availability of SSE2 intrinsics.
+ *
+ * If 'unsigned long' is a 64-bit type, then we assume that 64-bit types
+ * are efficient. Otherwise, we rely on macros that depend on compiler,
+ * OS and architecture. In any case, failure to detect the architecture
+ * as 64-bit means that the 32-bit code will be used, and that code
+ * works also on 64-bit architectures (the 64-bit code may simply be
+ * more efficient).
+ *
+ * The test on 'unsigned long' should already catch most cases, the one
+ * notable exception being Windows code where 'unsigned long' is kept to
+ * 32-bit for compatbility with all the legacy code that liberally uses
+ * the 'DWORD' type for 32-bit values.
+ *
+ * Macro names are taken from: http://nadeausoftware.com/articles/2012/02/c_c_tip_how_detect_processor_type_using_compiler_predefined_macros
+ */
+#ifndef BR_64
+#if ((ULONG_MAX >> 31) >> 31) == 3
+#define BR_64 1
+#elif defined(__ia64) || defined(__itanium__) || defined(_M_IA64)
+#define BR_64 1
+#elif defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__) \
+ || defined(__64BIT__) || defined(_LP64) || defined(__LP64__)
+#define BR_64 1
+#elif defined(__sparc64__)
+#define BR_64 1
+#elif defined(__x86_64__) || defined(_M_X64)
+#define BR_64 1
+#endif
+#endif
+
+/* ==================================================================== */
+/*
+ * Encoding/decoding functions.
+ *
+ * 32-bit and 64-bit decoding, both little-endian and big-endian, is
+ * implemented with the inline functions below. These functions are
+ * generic: they don't depend on the architecture natural endianness,
+ * and they can handle unaligned accesses. Optimized versions for some
+ * specific architectures may be implemented at a later time.
+ */
+
+static inline void
+br_enc16le(void *dst, unsigned x)
+{
+ unsigned char *buf;
+
+ buf = dst;
+ buf[0] = (unsigned char)x;
+ buf[1] = (unsigned char)(x >> 8);
+}
+
+static inline void
+br_enc16be(void *dst, unsigned x)
+{
+ unsigned char *buf;
+
+ buf = dst;
+ buf[0] = (unsigned char)(x >> 8);
+ buf[1] = (unsigned char)x;
+}
+
+static inline unsigned
+br_dec16le(const void *src)
+{
+ const unsigned char *buf;
+
+ buf = src;
+ return (unsigned)buf[0] | ((unsigned)buf[1] << 8);
+}
+
+static inline unsigned
+br_dec16be(const void *src)
+{
+ const unsigned char *buf;
+
+ buf = src;
+ return ((unsigned)buf[0] << 8) | (unsigned)buf[1];
+}
+
+static inline void
+br_enc32le(void *dst, uint32_t x)
+{
+ unsigned char *buf;
+
+ buf = dst;
+ buf[0] = (unsigned char)x;
+ buf[1] = (unsigned char)(x >> 8);
+ buf[2] = (unsigned char)(x >> 16);
+ buf[3] = (unsigned char)(x >> 24);
+}
+
+static inline void
+br_enc32be(void *dst, uint32_t x)
+{
+ unsigned char *buf;
+
+ buf = dst;
+ buf[0] = (unsigned char)(x >> 24);
+ buf[1] = (unsigned char)(x >> 16);
+ buf[2] = (unsigned char)(x >> 8);
+ buf[3] = (unsigned char)x;
+}
+
+static inline uint32_t
+br_dec32le(const void *src)
+{
+ const unsigned char *buf;
+
+ buf = src;
+ return (uint32_t)buf[0]
+ | ((uint32_t)buf[1] << 8)
+ | ((uint32_t)buf[2] << 16)
+ | ((uint32_t)buf[3] << 24);
+}
+
+static inline uint32_t
+br_dec32be(const void *src)
+{
+ const unsigned char *buf;
+
+ buf = src;
+ return ((uint32_t)buf[0] << 24)
+ | ((uint32_t)buf[1] << 16)
+ | ((uint32_t)buf[2] << 8)
+ | (uint32_t)buf[3];
+}
+
+static inline void
+br_enc64le(void *dst, uint64_t x)
+{
+ unsigned char *buf;
+
+ buf = dst;
+ br_enc32le(buf, (uint32_t)x);
+ br_enc32le(buf + 4, (uint32_t)(x >> 32));
+}
+
+static inline void
+br_enc64be(void *dst, uint64_t x)
+{
+ unsigned char *buf;
+
+ buf = dst;
+ br_enc32be(buf, (uint32_t)(x >> 32));
+ br_enc32be(buf + 4, (uint32_t)x);
+}
+
+static inline uint64_t
+br_dec64le(const void *src)
+{
+ const unsigned char *buf;
+
+ buf = src;
+ return (uint64_t)br_dec32le(buf)
+ | ((uint64_t)br_dec32le(buf + 4) << 32);
+}
+
+static inline uint64_t
+br_dec64be(const void *src)
+{
+ const unsigned char *buf;
+
+ buf = src;
+ return ((uint64_t)br_dec32be(buf) << 32)
+ | (uint64_t)br_dec32be(buf + 4);
+}
+
+/*
+ * Range decoding and encoding (for several successive values).
+ */
+void br_range_dec16le(uint16_t *v, size_t num, const void *src);
+void br_range_dec16be(uint16_t *v, size_t num, const void *src);
+void br_range_enc16le(void *dst, const uint16_t *v, size_t num);
+void br_range_enc16be(void *dst, const uint16_t *v, size_t num);
+
+void br_range_dec32le(uint32_t *v, size_t num, const void *src);
+void br_range_dec32be(uint32_t *v, size_t num, const void *src);
+void br_range_enc32le(void *dst, const uint32_t *v, size_t num);
+void br_range_enc32be(void *dst, const uint32_t *v, size_t num);
+
+void br_range_dec64le(uint64_t *v, size_t num, const void *src);
+void br_range_dec64be(uint64_t *v, size_t num, const void *src);
+void br_range_enc64le(void *dst, const uint64_t *v, size_t num);
+void br_range_enc64be(void *dst, const uint64_t *v, size_t num);
+
+/*
+ * Byte-swap a 32-bit integer.
+ */
+static inline uint32_t
+br_swap32(uint32_t x)
+{
+ x = ((x & (uint32_t)0x00FF00FF) << 8)
+ | ((x >> 8) & (uint32_t)0x00FF00FF);
+ return (x << 16) | (x >> 16);
+}
+
+/* ==================================================================== */
+/*
+ * Support code for hash functions.
+ */
+
+/*
+ * IV for MD5, SHA-1, SHA-224 and SHA-256.
+ */
+extern const uint32_t br_md5_IV[];
+extern const uint32_t br_sha1_IV[];
+extern const uint32_t br_sha224_IV[];
+extern const uint32_t br_sha256_IV[];
+
+/*
+ * Round functions for MD5, SHA-1, SHA-224 and SHA-256 (SHA-224 and
+ * SHA-256 use the same round function).
+ */
+void br_md5_round(const unsigned char *buf, uint32_t *val);
+void br_sha1_round(const unsigned char *buf, uint32_t *val);
+void br_sha2small_round(const unsigned char *buf, uint32_t *val);
+
+/*
+ * The core function for the TLS PRF. It computes
+ * P_hash(secret, label + seed), and XORs the result into the dst buffer.
+ */
+void br_tls_phash(void *dst, size_t len,
+ const br_hash_class *dig,
+ const void *secret, size_t secret_len,
+ const char *label, const void *seed, size_t seed_len);
+
+/*
+ * Copy all configured hash implementations from a multihash context
+ * to another.
+ */
+static inline void
+br_multihash_copyimpl(br_multihash_context *dst,
+ const br_multihash_context *src)
+{
+ memcpy(dst->impl, src->impl, sizeof src->impl);
+}
+
+/* ==================================================================== */
+/*
+ * Constant-time primitives. These functions manipulate 32-bit values in
+ * order to provide constant-time comparisons and multiplexers.
+ *
+ * Boolean values (the "ctl" bits) MUST have value 0 or 1.
+ *
+ * Implementation notes:
+ * =====================
+ *
+ * The uintN_t types are unsigned and with width exactly N bits; the C
+ * standard guarantees that computations are performed modulo 2^N, and
+ * there can be no overflow. Negation (unary '-') works on unsigned types
+ * as well.
+ *
+ * The intN_t types are guaranteed to have width exactly N bits, with no
+ * padding bit, and using two's complement representation. Casting
+ * intN_t to uintN_t really is conversion modulo 2^N. Beware that intN_t
+ * types, being signed, trigger implementation-defined behaviour on
+ * overflow (including raising some signal): with GCC, while modular
+ * arithmetics are usually applied, the optimizer may assume that
+ * overflows don't occur (unless the -fwrapv command-line option is
+ * added); Clang has the additional -ftrapv option to explicitly trap on
+ * integer overflow or underflow.
+ */
+
+/*
+ * Negate a boolean.
+ */
+static inline uint32_t
+NOT(uint32_t ctl)
+{
+ return ctl ^ 1;
+}
+
+/*
+ * Multiplexer: returns x if ctl == 1, y if ctl == 0.
+ */
+static inline uint32_t
+MUX(uint32_t ctl, uint32_t x, uint32_t y)
+{
+ return y ^ (-ctl & (x ^ y));
+}
+
+/*
+ * Equality check: returns 1 if x == y, 0 otherwise.
+ */
+static inline uint32_t
+EQ(uint32_t x, uint32_t y)
+{
+ uint32_t q;
+
+ q = x ^ y;
+ return NOT((q | -q) >> 31);
+}
+
+/*
+ * Inequality check: returns 1 if x != y, 0 otherwise.
+ */
+static inline uint32_t
+NEQ(uint32_t x, uint32_t y)
+{
+ uint32_t q;
+
+ q = x ^ y;
+ return (q | -q) >> 31;
+}
+
+/*
+ * Comparison: returns 1 if x > y, 0 otherwise.
+ */
+static inline uint32_t
+GT(uint32_t x, uint32_t y)
+{
+ /*
+ * If both x < 2^31 and x < 2^31, then y-x will have its high
+ * bit set if x > y, cleared otherwise.
+ *
+ * If either x >= 2^31 or y >= 2^31 (but not both), then the
+ * result is the high bit of x.
+ *
+ * If both x >= 2^31 and y >= 2^31, then we can virtually
+ * subtract 2^31 from both, and we are back to the first case.
+ * Since (y-2^31)-(x-2^31) = y-x, the subtraction is already
+ * fine.
+ */
+ uint32_t z;
+
+ z = y - x;
+ return (z ^ ((x ^ y) & (x ^ z))) >> 31;
+}
+
+/*
+ * Other comparisons (greater-or-equal, lower-than, lower-or-equal).
+ */
+#define GE(x, y) NOT(GT(y, x))
+#define LT(x, y) GT(y, x)
+#define LE(x, y) NOT(GT(x, y))
+
+/*
+ * General comparison: returned value is -1, 0 or 1, depending on
+ * whether x is lower than, equal to, or greater than y.
+ */
+static inline int32_t
+CMP(uint32_t x, uint32_t y)
+{
+ return (int32_t)GT(x, y) | -(int32_t)GT(y, x);
+}
+
+/*
+ * Returns 1 if x == 0, 0 otherwise. Take care that the operand is signed.
+ */
+static inline uint32_t
+EQ0(int32_t x)
+{
+ uint32_t q;
+
+ q = (uint32_t)x;
+ return ~(q | -q) >> 31;
+}
+
+/*
+ * Returns 1 if x > 0, 0 otherwise. Take care that the operand is signed.
+ */
+static inline uint32_t
+GT0(int32_t x)
+{
+ /*
+ * High bit of -x is 0 if x == 0, but 1 if x > 0.
+ */
+ uint32_t q;
+
+ q = (uint32_t)x;
+ return (~q & -q) >> 31;
+}
+
+/*
+ * Returns 1 if x >= 0, 0 otherwise. Take care that the operand is signed.
+ */
+static inline uint32_t
+GE0(int32_t x)
+{
+ return ~(uint32_t)x >> 31;
+}
+
+/*
+ * Returns 1 if x < 0, 0 otherwise. Take care that the operand is signed.
+ */
+static inline uint32_t
+LT0(int32_t x)
+{
+ return (uint32_t)x >> 31;
+}
+
+/*
+ * Returns 1 if x <= 0, 0 otherwise. Take care that the operand is signed.
+ */
+static inline uint32_t
+LE0(int32_t x)
+{
+ uint32_t q;
+
+ /*
+ * ~-x has its high bit set if and only if -x is nonnegative (as
+ * a signed int), i.e. x is in the -(2^31-1) to 0 range. We must
+ * do an OR with x itself to account for x = -2^31.
+ */
+ q = (uint32_t)x;
+ return (q | ~-q) >> 31;
+}
+
+/*
+ * Conditional copy: src[] is copied into dst[] if and only if ctl is 1.
+ * dst[] and src[] may overlap completely (but not partially).
+ */
+void br_ccopy(uint32_t ctl, void *dst, const void *src, size_t len);
+
+#define CCOPY br_ccopy
+
+/*
+ * Compute the bit length of a 32-bit integer. Returned value is between 0
+ * and 32 (inclusive).
+ */
+static inline uint32_t
+BIT_LENGTH(uint32_t x)
+{
+ uint32_t k, c;
+
+ k = NEQ(x, 0);
+ c = GT(x, 0xFFFF); x = MUX(c, x >> 16, x); k += c << 4;
+ c = GT(x, 0x00FF); x = MUX(c, x >> 8, x); k += c << 3;
+ c = GT(x, 0x000F); x = MUX(c, x >> 4, x); k += c << 2;
+ c = GT(x, 0x0003); x = MUX(c, x >> 2, x); k += c << 1;
+ k += GT(x, 0x0001);
+ return k;
+}
+
+/*
+ * Compute the minimum of x and y.
+ */
+static inline uint32_t
+MIN(uint32_t x, uint32_t y)
+{
+ return MUX(GT(x, y), y, x);
+}
+
+/*
+ * Compute the maximum of x and y.
+ */
+static inline uint32_t
+MAX(uint32_t x, uint32_t y)
+{
+ return MUX(GT(x, y), x, y);
+}
+
+/*
+ * Multiply two 32-bit integers, with a 64-bit result. This default
+ * implementation assumes that the basic multiplication operator
+ * yields constant-time code.
+ */
+#define MUL(x, y) ((uint64_t)(x) * (uint64_t)(y))
+
+#if BR_CT_MUL31
+
+/*
+ * Alternate implementation of MUL31, that will be constant-time on some
+ * (old) platforms where the default MUL31 is not. Unfortunately, it is
+ * also substantially slower, and yields larger code, on more modern
+ * platforms, which is why it is deactivated by default.
+ */
+#define MUL31(x, y) ((uint64_t)((x) | (uint32_t)0x80000000) \
+ * (uint64_t)((y) | (uint32_t)0x80000000) \
+ - ((uint64_t)(x) << 31) - ((uint64_t)(y) << 31) \
+ - ((uint64_t)1 << 62))
+
+#else
+
+/*
+ * Multiply two 31-bit integers, with a 62-bit result. This default
+ * implementation assumes that the basic multiplication operator
+ * yields constant-time code.
+ */
+#define MUL31(x, y) ((uint64_t)(x) * (uint64_t)(y))
+
+#endif
+
+/*
+ * Constant-time division. The dividend hi:lo is divided by the
+ * divisor d; the quotient is returned and the remainder is written
+ * in *r. If hi == d, then the quotient does not fit on 32 bits;
+ * returned value is thus truncated. If hi > d, returned values are
+ * indeterminate.
+ */
+uint32_t br_divrem(uint32_t hi, uint32_t lo, uint32_t d, uint32_t *r);
+
+/*
+ * Wrapper for br_divrem(); the remainder is returned, and the quotient
+ * is discarded.
+ */
+static inline uint32_t
+br_rem(uint32_t hi, uint32_t lo, uint32_t d)
+{
+ uint32_t r;
+
+ br_divrem(hi, lo, d, &r);
+ return r;
+}
+
+/*
+ * Wrapper for br_divrem(); the quotient is returned, and the remainder
+ * is discarded.
+ */
+static inline uint32_t
+br_div(uint32_t hi, uint32_t lo, uint32_t d)
+{
+ uint32_t r;
+
+ return br_divrem(hi, lo, d, &r);
+}
+
+/* ==================================================================== */
+
+/*
+ * Integers 'i32'
+ * --------------
+ *
+ * The 'i32' functions implement computations on big integers using
+ * an internal representation as an array of 32-bit integers. For
+ * an array x[]:
+ * -- x[0] contains the "announced bit length" of the integer
+ * -- x[1], x[2]... contain the value in little-endian order (x[1]
+ * contains the least significant 32 bits)
+ *
+ * Multiplications rely on the elementary 32x32->64 multiplication.
+ *
+ * The announced bit length specifies the number of bits that are
+ * significant in the subsequent 32-bit words. Unused bits in the
+ * last (most significant) word are set to 0; subsequent words are
+ * uninitialized and need not exist at all.
+ *
+ * The execution time and memory access patterns of all computations
+ * depend on the announced bit length, but not on the actual word
+ * values. For modular integers, the announced bit length of any integer
+ * modulo n is equal to the actual bit length of n; thus, computations
+ * on modular integers are "constant-time" (only the modulus length may
+ * leak).
+ */
+
+/*
+ * Compute the actual bit length of an integer. The argument x should
+ * point to the first (least significant) value word of the integer.
+ * The len 'xlen' contains the number of 32-bit words to access.
+ *
+ * CT: value or length of x does not leak.
+ */
+uint32_t br_i32_bit_length(uint32_t *x, size_t xlen);
+
+/*
+ * Decode an integer from its big-endian unsigned representation. The
+ * "true" bit length of the integer is computed, but all words of x[]
+ * corresponding to the full 'len' bytes of the source are set.
+ *
+ * CT: value or length of x does not leak.
+ */
+void br_i32_decode(uint32_t *x, const void *src, size_t len);
+
+/*
+ * Decode an integer from its big-endian unsigned representation. The
+ * integer MUST be lower than m[]; the announced bit length written in
+ * x[] will be equal to that of m[]. All 'len' bytes from the source are
+ * read.
+ *
+ * Returned value is 1 if the decode value fits within the modulus, 0
+ * otherwise. In the latter case, the x[] buffer will be set to 0 (but
+ * still with the announced bit length of m[]).
+ *
+ * CT: value or length of x does not leak. Memory access pattern depends
+ * only of 'len' and the announced bit length of m. Whether x fits or
+ * not does not leak either.
+ */
+uint32_t br_i32_decode_mod(uint32_t *x,
+ const void *src, size_t len, const uint32_t *m);
+
+/*
+ * Reduce an integer (a[]) modulo another (m[]). The result is written
+ * in x[] and its announced bit length is set to be equal to that of m[].
+ *
+ * x[] MUST be distinct from a[] and m[].
+ *
+ * CT: only announced bit lengths leak, not values of x, a or m.
+ */
+void br_i32_reduce(uint32_t *x, const uint32_t *a, const uint32_t *m);
+
+/*
+ * Decode an integer from its big-endian unsigned representation, and
+ * reduce it modulo the provided modulus m[]. The announced bit length
+ * of the result is set to be equal to that of the modulus.
+ *
+ * x[] MUST be distinct from m[].
+ */
+void br_i32_decode_reduce(uint32_t *x,
+ const void *src, size_t len, const uint32_t *m);
+
+/*
+ * Encode an integer into its big-endian unsigned representation. The
+ * output length in bytes is provided (parameter 'len'); if the length
+ * is too short then the integer is appropriately truncated; if it is
+ * too long then the extra bytes are set to 0.
+ */
+void br_i32_encode(void *dst, size_t len, const uint32_t *x);
+
+/*
+ * Multiply x[] by 2^32 and then add integer z, modulo m[]. This
+ * function assumes that x[] and m[] have the same announced bit
+ * length, and the announced bit length of m[] matches its true
+ * bit length.
+ *
+ * x[] and m[] MUST be distinct arrays.
+ *
+ * CT: only the common announced bit length of x and m leaks, not
+ * the values of x, z or m.
+ */
+void br_i32_muladd_small(uint32_t *x, uint32_t z, const uint32_t *m);
+
+/*
+ * Extract one word from an integer. The offset is counted in bits.
+ * The word MUST entirely fit within the word elements corresponding
+ * to the announced bit length of a[].
+ */
+static inline uint32_t
+br_i32_word(const uint32_t *a, uint32_t off)
+{
+ size_t u;
+ unsigned j;
+
+ u = (size_t)(off >> 5) + 1;
+ j = (unsigned)off & 31;
+ if (j == 0) {
+ return a[u];
+ } else {
+ return (a[u] >> j) | (a[u + 1] << (32 - j));
+ }
+}
+
+/*
+ * Test whether an integer is zero.
+ */
+uint32_t br_i32_iszero(const uint32_t *x);
+
+/*
+ * Add b[] to a[] and return the carry (0 or 1). If ctl is 0, then a[]
+ * is unmodified, but the carry is still computed and returned. The
+ * arrays a[] and b[] MUST have the same announced bit length.
+ *
+ * a[] and b[] MAY be the same array, but partial overlap is not allowed.
+ */
+uint32_t br_i32_add(uint32_t *a, const uint32_t *b, uint32_t ctl);
+
+/*
+ * Subtract b[] from a[] and return the carry (0 or 1). If ctl is 0,
+ * then a[] is unmodified, but the carry is still computed and returned.
+ * The arrays a[] and b[] MUST have the same announced bit length.
+ *
+ * a[] and b[] MAY be the same array, but partial overlap is not allowed.
+ */
+uint32_t br_i32_sub(uint32_t *a, const uint32_t *b, uint32_t ctl);
+
+/*
+ * Compute d+a*b, result in d. The initial announced bit length of d[]
+ * MUST match that of a[]. The d[] array MUST be large enough to
+ * accommodate the full result, plus (possibly) an extra word. The
+ * resulting announced bit length of d[] will be the sum of the announced
+ * bit lengths of a[] and b[] (therefore, it may be larger than the actual
+ * bit length of the numerical result).
+ *
+ * a[] and b[] may be the same array. d[] must be disjoint from both a[]
+ * and b[].
+ */
+void br_i32_mulacc(uint32_t *d, const uint32_t *a, const uint32_t *b);
+
+/*
+ * Zeroize an integer. The announced bit length is set to the provided
+ * value, and the corresponding words are set to 0.
+ */
+static inline void
+br_i32_zero(uint32_t *x, uint32_t bit_len)
+{
+ *x ++ = bit_len;
+ memset(x, 0, ((bit_len + 31) >> 5) * sizeof *x);
+}
+
+/*
+ * Compute -(1/x) mod 2^32. If x is even, then this function returns 0.
+ */
+uint32_t br_i32_ninv32(uint32_t x);
+
+/*
+ * Convert a modular integer to Montgomery representation. The integer x[]
+ * MUST be lower than m[], but with the same announced bit length.
+ */
+void br_i32_to_monty(uint32_t *x, const uint32_t *m);
+
+/*
+ * Convert a modular integer back from Montgomery representation. The
+ * integer x[] MUST be lower than m[], but with the same announced bit
+ * length. The "m0i" parameter is equal to -(1/m0) mod 2^32, where m0 is
+ * the least significant value word of m[] (this works only if m[] is
+ * an odd integer).
+ */
+void br_i32_from_monty(uint32_t *x, const uint32_t *m, uint32_t m0i);
+
+/*
+ * Compute a modular Montgomery multiplication. d[] is filled with the
+ * value of x*y/R modulo m[] (where R is the Montgomery factor). The
+ * array d[] MUST be distinct from x[], y[] and m[]. x[] and y[] MUST be
+ * numerically lower than m[]. x[] and y[] MAY be the same array. The
+ * "m0i" parameter is equal to -(1/m0) mod 2^32, where m0 is the least
+ * significant value word of m[] (this works only if m[] is an odd
+ * integer).
+ */
+void br_i32_montymul(uint32_t *d, const uint32_t *x, const uint32_t *y,
+ const uint32_t *m, uint32_t m0i);
+
+/*
+ * Compute a modular exponentiation. x[] MUST be an integer modulo m[]
+ * (same announced bit length, lower value). m[] MUST be odd. The
+ * exponent is in big-endian unsigned notation, over 'elen' bytes. The
+ * "m0i" parameter is equal to -(1/m0) mod 2^32, where m0 is the least
+ * significant value word of m[] (this works only if m[] is an odd
+ * integer). The t1[] and t2[] parameters must be temporary arrays,
+ * each large enough to accommodate an integer with the same size as m[].
+ */
+void br_i32_modpow(uint32_t *x, const unsigned char *e, size_t elen,
+ const uint32_t *m, uint32_t m0i, uint32_t *t1, uint32_t *t2);
+
+/* ==================================================================== */
+
+/*
+ * Integers 'i31'
+ * --------------
+ *
+ * The 'i31' functions implement computations on big integers using
+ * an internal representation as an array of 32-bit integers. For
+ * an array x[]:
+ * -- x[0] encodes the array length and the "announced bit length"
+ * of the integer: namely, if the announced bit length is k,
+ * then x[0] = ((k / 31) << 5) + (k % 31).
+ * -- x[1], x[2]... contain the value in little-endian order, 31
+ * bits per word (x[1] contains the least significant 31 bits).
+ * The upper bit of each word is 0.
+ *
+ * Multiplications rely on the elementary 32x32->64 multiplication.
+ *
+ * The announced bit length specifies the number of bits that are
+ * significant in the subsequent 32-bit words. Unused bits in the
+ * last (most significant) word are set to 0; subsequent words are
+ * uninitialized and need not exist at all.
+ *
+ * The execution time and memory access patterns of all computations
+ * depend on the announced bit length, but not on the actual word
+ * values. For modular integers, the announced bit length of any integer
+ * modulo n is equal to the actual bit length of n; thus, computations
+ * on modular integers are "constant-time" (only the modulus length may
+ * leak).
+ */
+
+/*
+ * Test whether an integer is zero.
+ */
+uint32_t br_i31_iszero(const uint32_t *x);
+
+/*
+ * Add b[] to a[] and return the carry (0 or 1). If ctl is 0, then a[]
+ * is unmodified, but the carry is still computed and returned. The
+ * arrays a[] and b[] MUST have the same announced bit length.
+ *
+ * a[] and b[] MAY be the same array, but partial overlap is not allowed.
+ */
+uint32_t br_i31_add(uint32_t *a, const uint32_t *b, uint32_t ctl);
+
+/*
+ * Subtract b[] from a[] and return the carry (0 or 1). If ctl is 0,
+ * then a[] is unmodified, but the carry is still computed and returned.
+ * The arrays a[] and b[] MUST have the same announced bit length.
+ *
+ * a[] and b[] MAY be the same array, but partial overlap is not allowed.
+ */
+uint32_t br_i31_sub(uint32_t *a, const uint32_t *b, uint32_t ctl);
+
+/*
+ * Compute the ENCODED actual bit length of an integer. The argument x
+ * should point to the first (least significant) value word of the
+ * integer. The len 'xlen' contains the number of 32-bit words to
+ * access. The upper bit of each value word MUST be 0.
+ * Returned value is ((k / 31) << 5) + (k % 31) if the bit length is k.
+ *
+ * CT: value or length of x does not leak.
+ */
+uint32_t br_i31_bit_length(uint32_t *x, size_t xlen);
+
+/*
+ * Decode an integer from its big-endian unsigned representation. The
+ * "true" bit length of the integer is computed and set in the encoded
+ * announced bit length (x[0]), but all words of x[] corresponding to
+ * the full 'len' bytes of the source are set.
+ *
+ * CT: value or length of x does not leak.
+ */
+void br_i31_decode(uint32_t *x, const void *src, size_t len);
+
+/*
+ * Decode an integer from its big-endian unsigned representation. The
+ * integer MUST be lower than m[]; the (encoded) announced bit length
+ * written in x[] will be equal to that of m[]. All 'len' bytes from the
+ * source are read.
+ *
+ * Returned value is 1 if the decode value fits within the modulus, 0
+ * otherwise. In the latter case, the x[] buffer will be set to 0 (but
+ * still with the announced bit length of m[]).
+ *
+ * CT: value or length of x does not leak. Memory access pattern depends
+ * only of 'len' and the announced bit length of m. Whether x fits or
+ * not does not leak either.
+ */
+uint32_t br_i31_decode_mod(uint32_t *x,
+ const void *src, size_t len, const uint32_t *m);
+
+/*
+ * Zeroize an integer. The announced bit length is set to the provided
+ * value, and the corresponding words are set to 0. The ENCODED bit length
+ * is expected here.
+ */
+static inline void
+br_i31_zero(uint32_t *x, uint32_t bit_len)
+{
+ *x ++ = bit_len;
+ memset(x, 0, ((bit_len + 31) >> 5) * sizeof *x);
+}
+
+/*
+ * Right-shift an integer. The shift amount must be lower than 31
+ * bits.
+ */
+void br_i31_rshift(uint32_t *x, int count);
+
+/*
+ * Reduce an integer (a[]) modulo another (m[]). The result is written
+ * in x[] and its announced bit length is set to be equal to that of m[].
+ *
+ * x[] MUST be distinct from a[] and m[].
+ *
+ * CT: only announced bit lengths leak, not values of x, a or m.
+ */
+void br_i31_reduce(uint32_t *x, const uint32_t *a, const uint32_t *m);
+
+/*
+ * Decode an integer from its big-endian unsigned representation, and
+ * reduce it modulo the provided modulus m[]. The announced bit length
+ * of the result is set to be equal to that of the modulus.
+ *
+ * x[] MUST be distinct from m[].
+ */
+void br_i31_decode_reduce(uint32_t *x,
+ const void *src, size_t len, const uint32_t *m);
+
+/*
+ * Multiply x[] by 2^31 and then add integer z, modulo m[]. This
+ * function assumes that x[] and m[] have the same announced bit
+ * length, the announced bit length of m[] matches its true
+ * bit length.
+ *
+ * x[] and m[] MUST be distinct arrays. z MUST fit in 31 bits (upper
+ * bit set to 0).
+ *
+ * CT: only the common announced bit length of x and m leaks, not
+ * the values of x, z or m.
+ */
+void br_i31_muladd_small(uint32_t *x, uint32_t z, const uint32_t *m);
+
+/*
+ * Encode an integer into its big-endian unsigned representation. The
+ * output length in bytes is provided (parameter 'len'); if the length
+ * is too short then the integer is appropriately truncated; if it is
+ * too long then the extra bytes are set to 0.
+ */
+void br_i31_encode(void *dst, size_t len, const uint32_t *x);
+
+/*
+ * Compute -(1/x) mod 2^31. If x is even, then this function returns 0.
+ */
+uint32_t br_i31_ninv31(uint32_t x);
+
+/*
+ * Compute a modular Montgomery multiplication. d[] is filled with the
+ * value of x*y/R modulo m[] (where R is the Montgomery factor). The
+ * array d[] MUST be distinct from x[], y[] and m[]. x[] and y[] MUST be
+ * numerically lower than m[]. x[] and y[] MAY be the same array. The
+ * "m0i" parameter is equal to -(1/m0) mod 2^31, where m0 is the least
+ * significant value word of m[] (this works only if m[] is an odd
+ * integer).
+ */
+void br_i31_montymul(uint32_t *d, const uint32_t *x, const uint32_t *y,
+ const uint32_t *m, uint32_t m0i);
+
+/*
+ * Convert a modular integer to Montgomery representation. The integer x[]
+ * MUST be lower than m[], but with the same announced bit length.
+ */
+void br_i31_to_monty(uint32_t *x, const uint32_t *m);
+
+/*
+ * Convert a modular integer back from Montgomery representation. The
+ * integer x[] MUST be lower than m[], but with the same announced bit
+ * length. The "m0i" parameter is equal to -(1/m0) mod 2^32, where m0 is
+ * the least significant value word of m[] (this works only if m[] is
+ * an odd integer).
+ */
+void br_i31_from_monty(uint32_t *x, const uint32_t *m, uint32_t m0i);
+
+/*
+ * Compute a modular exponentiation. x[] MUST be an integer modulo m[]
+ * (same announced bit length, lower value). m[] MUST be odd. The
+ * exponent is in big-endian unsigned notation, over 'elen' bytes. The
+ * "m0i" parameter is equal to -(1/m0) mod 2^31, where m0 is the least
+ * significant value word of m[] (this works only if m[] is an odd
+ * integer). The t1[] and t2[] parameters must be temporary arrays,
+ * each large enough to accommodate an integer with the same size as m[].
+ */
+void br_i31_modpow(uint32_t *x, const unsigned char *e, size_t elen,
+ const uint32_t *m, uint32_t m0i, uint32_t *t1, uint32_t *t2);
+
+/*
+ * Compute d+a*b, result in d. The initial announced bit length of d[]
+ * MUST match that of a[]. The d[] array MUST be large enough to
+ * accommodate the full result, plus (possibly) an extra word. The
+ * resulting announced bit length of d[] will be the sum of the announced
+ * bit lengths of a[] and b[] (therefore, it may be larger than the actual
+ * bit length of the numerical result).
+ *
+ * a[] and b[] may be the same array. d[] must be disjoint from both a[]
+ * and b[].
+ */
+void br_i31_mulacc(uint32_t *d, const uint32_t *a, const uint32_t *b);
+
+/* ==================================================================== */
+
+static inline size_t
+br_digest_size(const br_hash_class *digest_class)
+{
+ return (size_t)(digest_class->desc >> BR_HASHDESC_OUT_OFF)
+ & BR_HASHDESC_OUT_MASK;
+}
+
+/*
+ * Get the output size (in bytes) of a hash function.
+ */
+size_t br_digest_size_by_ID(int digest_id);
+
+/*
+ * Get the OID (encoded OBJECT IDENTIFIER value, without tag and length)
+ * for a hash function. If digest_id is not a supported digest identifier
+ * (in particular if it is equal to 0, i.e. br_md5sha1_ID), then NULL is
+ * returned and *len is set to 0.
+ */
+const unsigned char *br_digest_OID(int digest_id, size_t *len);
+
+/* ==================================================================== */
+/*
+ * DES support functions.
+ */
+
+/*
+ * Apply DES Initial Permutation.
+ */
+void br_des_do_IP(uint32_t *xl, uint32_t *xr);
+
+/*
+ * Apply DES Final Permutation (inverse of IP).
+ */
+void br_des_do_invIP(uint32_t *xl, uint32_t *xr);
+
+/*
+ * Key schedule unit: for a DES key (8 bytes), compute 16 subkeys. Each
+ * subkey is two 28-bit words represented as two 32-bit words; the PC-2
+ * bit extration is NOT applied.
+ */
+void br_des_keysched_unit(uint32_t *skey, const void *key);
+
+/*
+ * Reversal of 16 DES sub-keys (for decryption).
+ */
+void br_des_rev_skey(uint32_t *skey);
+
+/*
+ * DES/3DES key schedule for 'des_tab' (encryption direction). Returned
+ * value is the number of rounds.
+ */
+unsigned br_des_tab_keysched(uint32_t *skey, const void *key, size_t key_len);
+
+/*
+ * DES/3DES key schedule for 'des_ct' (encryption direction). Returned
+ * value is the number of rounds.
+ */
+unsigned br_des_ct_keysched(uint32_t *skey, const void *key, size_t key_len);
+
+/*
+ * DES/3DES subkey decompression (from the compressed bitsliced subkeys).
+ */
+void br_des_ct_skey_expand(uint32_t *sk_exp,
+ unsigned num_rounds, const uint32_t *skey);
+
+/*
+ * DES/3DES block encryption/decryption ('des_tab').
+ */
+void br_des_tab_process_block(unsigned num_rounds,
+ const uint32_t *skey, void *block);
+
+/*
+ * DES/3DES block encryption/decryption ('des_ct').
+ */
+void br_des_ct_process_block(unsigned num_rounds,
+ const uint32_t *skey, void *block);
+
+/* ==================================================================== */
+/*
+ * AES support functions.
+ */
+
+/*
+ * The AES S-box (256-byte table).
+ */
+extern const unsigned char br_aes_S[];
+
+/*
+ * AES key schedule. skey[] is filled with n+1 128-bit subkeys, where n
+ * is the number of rounds (10 to 14, depending on key size). The number
+ * of rounds is returned. If the key size is invalid (not 16, 24 or 32),
+ * then 0 is returned.
+ *
+ * This implementation uses a 256-byte table and is NOT constant-time.
+ */
+unsigned br_aes_keysched(uint32_t *skey, const void *key, size_t key_len);
+
+/*
+ * AES key schedule for decryption ('aes_big' implementation).
+ */
+unsigned br_aes_big_keysched_inv(uint32_t *skey,
+ const void *key, size_t key_len);
+
+/*
+ * AES block encryption with the 'aes_big' implementation (fast, but
+ * not constant-time). This function encrypts a single block "in place".
+ */
+void br_aes_big_encrypt(unsigned num_rounds, const uint32_t *skey, void *data);
+
+/*
+ * AES block decryption with the 'aes_big' implementation (fast, but
+ * not constant-time). This function decrypts a single block "in place".
+ */
+void br_aes_big_decrypt(unsigned num_rounds, const uint32_t *skey, void *data);
+
+/*
+ * AES block encryption with the 'aes_small' implementation (small, but
+ * slow and not constant-time). This function encrypts a single block
+ * "in place".
+ */
+void br_aes_small_encrypt(unsigned num_rounds,
+ const uint32_t *skey, void *data);
+
+/*
+ * AES block decryption with the 'aes_small' implementation (small, but
+ * slow and not constant-time). This function decrypts a single block
+ * "in place".
+ */
+void br_aes_small_decrypt(unsigned num_rounds,
+ const uint32_t *skey, void *data);
+
+/*
+ * The constant-time implementation is "bitsliced": the 128-bit state is
+ * split over eight 32-bit words q* in the following way:
+ *
+ * -- Input block consists in 16 bytes:
+ * a00 a10 a20 a30 a01 a11 a21 a31 a02 a12 a22 a32 a03 a13 a23 a33
+ * In the terminology of FIPS 197, this is a 4x4 matrix which is read
+ * column by column.
+ *
+ * -- Each byte is split into eight bits which are distributed over the
+ * eight words, at the same rank. Thus, for a byte x at rank k, bit 0
+ * (least significant) of x will be at rank k in q0 (if that bit is b,
+ * then it contributes "b << k" to the value of q0), bit 1 of x will be
+ * at rank k in q1, and so on.
+ *
+ * -- Ranks given to bits are in "row order" and are either all even, or
+ * all odd. Two independent AES states are thus interleaved, one using
+ * the even ranks, the other the odd ranks. Row order means:
+ * a00 a01 a02 a03 a10 a11 a12 a13 a20 a21 a22 a23 a30 a31 a32 a33
+ *
+ * Converting input bytes from two AES blocks to bitslice representation
+ * is done in the following way:
+ * -- Decode first block into the four words q0 q2 q4 q6, in that order,
+ * using little-endian convention.
+ * -- Decode second block into the four words q1 q3 q5 q7, in that order,
+ * using little-endian convention.
+ * -- Call br_aes_ct_ortho().
+ *
+ * Converting back to bytes is done by using the reverse operations. Note
+ * that br_aes_ct_ortho() is its own inverse.
+ */
+
+/*
+ * Perform bytewise orthogonalization of eight 32-bit words. Bytes
+ * of q0..q7 are spread over all words: for a byte x that occurs
+ * at rank i in q[j] (byte x uses bits 8*i to 8*i+7 in q[j]), the bit
+ * of rank k in x (0 <= k <= 7) goes to q[k] at rank 8*i+j.
+ *
+ * This operation is an involution.
+ */
+void br_aes_ct_ortho(uint32_t *q);
+
+/*
+ * The AES S-box, as a bitsliced constant-time version. The input array
+ * consists in eight 32-bit words; 32 S-box instances are computed in
+ * parallel. Bits 0 to 7 of each S-box input (bit 0 is least significant)
+ * are spread over the words 0 to 7, at the same rank.
+ */
+void br_aes_ct_bitslice_Sbox(uint32_t *q);
+
+/*
+ * Like br_aes_bitslice_Sbox(), but for the inverse S-box.
+ */
+void br_aes_ct_bitslice_invSbox(uint32_t *q);
+
+/*
+ * Compute AES encryption on bitsliced data. Since input is stored on
+ * eight 32-bit words, two block encryptions are actually performed
+ * in parallel.
+ */
+void br_aes_ct_bitslice_encrypt(unsigned num_rounds,
+ const uint32_t *skey, uint32_t *q);
+
+/*
+ * Compute AES decryption on bitsliced data. Since input is stored on
+ * eight 32-bit words, two block decryptions are actually performed
+ * in parallel.
+ */
+void br_aes_ct_bitslice_decrypt(unsigned num_rounds,
+ const uint32_t *skey, uint32_t *q);
+
+/*
+ * AES key schedule, constant-time version. skey[] is filled with n+1
+ * 128-bit subkeys, where n is the number of rounds (10 to 14, depending
+ * on key size). The number of rounds is returned. If the key size is
+ * invalid (not 16, 24 or 32), then 0 is returned.
+ */
+unsigned br_aes_ct_keysched(uint32_t *comp_skey,
+ const void *key, size_t key_len);
+
+/*
+ * Expand AES subkeys as produced by br_aes_ct_keysched(), into
+ * a larger array suitable for br_aes_ct_bitslice_encrypt() and
+ * br_aes_ct_bitslice_decrypt().
+ */
+void br_aes_ct_skey_expand(uint32_t *skey,
+ unsigned num_rounds, const uint32_t *comp_skey);
+
+/*
+ * For the ct64 implementation, the same bitslicing technique is used,
+ * but four instances are interleaved. First instance uses bits 0, 4,
+ * 8, 12,... of each word; second instance uses bits 1, 5, 9, 13,...
+ * and so on.
+ */
+
+/*
+ * Perform bytewise orthogonalization of eight 64-bit words. Bytes
+ * of q0..q7 are spread over all words: for a byte x that occurs
+ * at rank i in q[j] (byte x uses bits 8*i to 8*i+7 in q[j]), the bit
+ * of rank k in x (0 <= k <= 7) goes to q[k] at rank 8*i+j.
+ *
+ * This operation is an involution.
+ */
+void br_aes_ct64_ortho(uint64_t *q);
+
+/*
+ * Interleave bytes for an AES input block. If input bytes are
+ * denoted 0123456789ABCDEF, and have been decoded with little-endian
+ * convention (w[0] contains 0123, with '3' being most significant;
+ * w[1] contains 4567, and so on), then output word q0 will be
+ * set to 08192A3B (again little-endian convention) and q1 will
+ * be set to 4C5D6E7F.
+ */
+void br_aes_ct64_interleave_in(uint64_t *q0, uint64_t *q1, const uint32_t *w);
+
+/*
+ * Perform the opposite of br_aes_ct64_interleave_in().
+ */
+void br_aes_ct64_interleave_out(uint32_t *w, uint64_t q0, uint64_t q1);
+
+/*
+ * The AES S-box, as a bitsliced constant-time version. The input array
+ * consists in eight 64-bit words; 64 S-box instances are computed in
+ * parallel. Bits 0 to 7 of each S-box input (bit 0 is least significant)
+ * are spread over the words 0 to 7, at the same rank.
+ */
+void br_aes_ct64_bitslice_Sbox(uint64_t *q);
+
+/*
+ * Like br_aes_bitslice_Sbox(), but for the inverse S-box.
+ */
+void br_aes_ct64_bitslice_invSbox(uint64_t *q);
+
+/*
+ * Compute AES encryption on bitsliced data. Since input is stored on
+ * eight 64-bit words, four block encryptions are actually performed
+ * in parallel.
+ */
+void br_aes_ct64_bitslice_encrypt(unsigned num_rounds,
+ const uint64_t *skey, uint64_t *q);
+
+/*
+ * Compute AES decryption on bitsliced data. Since input is stored on
+ * eight 64-bit words, four block decryptions are actually performed
+ * in parallel.
+ */
+void br_aes_ct64_bitslice_decrypt(unsigned num_rounds,
+ const uint64_t *skey, uint64_t *q);
+
+/*
+ * AES key schedule, constant-time version. skey[] is filled with n+1
+ * 128-bit subkeys, where n is the number of rounds (10 to 14, depending
+ * on key size). The number of rounds is returned. If the key size is
+ * invalid (not 16, 24 or 32), then 0 is returned.
+ */
+unsigned br_aes_ct64_keysched(uint64_t *comp_skey,
+ const void *key, size_t key_len);
+
+/*
+ * Expand AES subkeys as produced by br_aes_ct64_keysched(), into
+ * a larger array suitable for br_aes_ct64_bitslice_encrypt() and
+ * br_aes_ct64_bitslice_decrypt().
+ */
+void br_aes_ct64_skey_expand(uint64_t *skey,
+ unsigned num_rounds, const uint64_t *comp_skey);
+
+/* ==================================================================== */
+/*
+ * Elliptic curves.
+ */
+
+/*
+ * Type for generic EC parameters: curve order (unsigned big-endian
+ * encoding) and encoded conventional generator.
+ */
+typedef struct {
+ int curve;
+ const unsigned char *order;
+ size_t order_len;
+ const unsigned char *generator;
+ size_t generator_len;
+} br_ec_curve_def;
+
+extern const br_ec_curve_def br_secp256r1;
+extern const br_ec_curve_def br_secp384r1;
+extern const br_ec_curve_def br_secp521r1;
+
+/*
+ * Type for the parameters for a "prime curve":
+ * coordinates are in GF(p), with p prime
+ * curve equation is Y^2 = X^3 - 3*X + b
+ * b is in Montgomery representation
+ * curve order is n and is prime
+ * base point is G (encoded) and has order n
+ */
+typedef struct {
+ const uint32_t *p;
+ const uint32_t *b;
+ const uint32_t p0i;
+} br_ec_prime_i31_curve;
+
+extern const br_ec_prime_i31_curve br_ec_prime_i31_secp256r1;
+extern const br_ec_prime_i31_curve br_ec_prime_i31_secp384r1;
+extern const br_ec_prime_i31_curve br_ec_prime_i31_secp521r1;
+
+#define BR_EC_I31_LEN ((BR_MAX_EC_SIZE + 61) / 31)
+
+/*
+ * Decode some bytes as an i31 integer, with truncation (corresponding
+ * to the 'bits2int' operation in RFC 6979). The target ENCODED bit
+ * length is provided as last parameter. The resulting value will have
+ * this declared bit length, and consists the big-endian unsigned decoding
+ * of exactly that many bits in the source (capped at the source length).
+ */
+void br_ecdsa_i31_bits2int(uint32_t *x,
+ const void *src, size_t len, uint32_t ebitlen);
+
+/* ==================================================================== */
+/*
+ * SSL/TLS support functions.
+ */
+
+/*
+ * Record types.
+ */
+#define BR_SSL_CHANGE_CIPHER_SPEC 20
+#define BR_SSL_ALERT 21
+#define BR_SSL_HANDSHAKE 22
+#define BR_SSL_APPLICATION_DATA 23
+
+/*
+ * Handshake message types.
+ */
+#define BR_SSL_HELLO_REQUEST 0
+#define BR_SSL_CLIENT_HELLO 1
+#define BR_SSL_SERVER_HELLO 2
+#define BR_SSL_CERTIFICATE 11
+#define BR_SSL_SERVER_KEY_EXCHANGE 12
+#define BR_SSL_CERTIFICATE_REQUEST 13
+#define BR_SSL_SERVER_HELLO_DONE 14
+#define BR_SSL_CERTIFICATE_VERIFY 15
+#define BR_SSL_CLIENT_KEY_EXCHANGE 16
+#define BR_SSL_FINISHED 20
+
+/*
+ * Alert levels.
+ */
+#define BR_LEVEL_WARNING 1
+#define BR_LEVEL_FATAL 2
+
+/*
+ * Low-level I/O state.
+ */
+#define BR_IO_FAILED 0
+#define BR_IO_IN 1
+#define BR_IO_OUT 2
+#define BR_IO_INOUT 3
+
+/*
+ * Mark a SSL engine as failed. The provided error code is recorded if
+ * the engine was not already marked as failed. If 'err' is 0, then the
+ * engine is marked as closed (without error).
+ */
+void br_ssl_engine_fail(br_ssl_engine_context *cc, int err);
+
+/*
+ * Test whether the engine is closed (normally or as a failure).
+ */
+static inline int
+br_ssl_engine_closed(const br_ssl_engine_context *cc)
+{
+ return cc->iomode == BR_IO_FAILED;
+}
+
+/*
+ * Configure a new maximum fragment length. If possible, the maximum
+ * length for outgoing records is immediately adjusted (if there are
+ * not already too many buffered bytes for that).
+ */
+void br_ssl_engine_new_max_frag_len(
+ br_ssl_engine_context *rc, unsigned max_frag_len);
+
+/*
+ * Test whether the current incoming record has been fully received
+ * or not. This functions returns 0 only if a complete record header
+ * has been received, but some of the (possibly encrypted) payload
+ * has not yet been obtained.
+ */
+int br_ssl_engine_recvrec_finished(const br_ssl_engine_context *rc);
+
+/*
+ * Flush the current record (if not empty). This is meant to be called
+ * from the handshake processor only.
+ */
+void br_ssl_engine_flush_record(br_ssl_engine_context *cc);
+
+/*
+ * Test whether there is some accumulated payload to send.
+ */
+static inline int
+br_ssl_engine_has_pld_to_send(const br_ssl_engine_context *rc)
+{
+ return rc->oxa != rc->oxb && rc->oxa != rc->oxc;
+}
+
+/*
+ * Initialize RNG in engine. Returned value is 1 on success, 0 on error.
+ * This function will try to use the OS-provided RNG, if available. If
+ * there is no OS-provided RNG, or if it failed, and no entropy was
+ * injected by the caller, then a failure will be reported. On error,
+ * the context error code is set.
+ */
+int br_ssl_engine_init_rand(br_ssl_engine_context *cc);
+
+/*
+ * Reset the handshake-related parts of the engine.
+ */
+void br_ssl_engine_hs_reset(br_ssl_engine_context *cc,
+ void (*hsinit)(void *), void (*hsrun)(void *));
+
+/*
+ * Get the PRF to use for this context, for the provided PRF hash
+ * function ID.
+ */
+br_tls_prf_impl br_ssl_engine_get_PRF(br_ssl_engine_context *cc, int prf_id);
+
+/*
+ * Consume the provided pre-master secret and compute the corresponding
+ * master secret. The 'prf_id' is the ID of the hash function to use
+ * with the TLS 1.2 PRF (ignored if the version is TLS 1.0 or 1.1).
+ */
+void br_ssl_engine_compute_master(br_ssl_engine_context *cc,
+ int prf_id, const void *pms, size_t len);
+
+/*
+ * Switch to CBC decryption for incoming records.
+ * cc the engine context
+ * is_client non-zero for a client, zero for a server
+ * prf_id id of hash function for PRF (ignored if not TLS 1.2+)
+ * mac_id id of hash function for HMAC
+ * bc_impl block cipher implementation (CBC decryption)
+ * cipher_key_len block cipher key length (in bytes)
+ */
+void br_ssl_engine_switch_cbc_in(br_ssl_engine_context *cc,
+ int is_client, int prf_id, int mac_id,
+ const br_block_cbcdec_class *bc_impl, size_t cipher_key_len);
+
+/*
+ * Switch to CBC encryption for outgoing records.
+ * cc the engine context
+ * is_client non-zero for a client, zero for a server
+ * prf_id id of hash function for PRF (ignored if not TLS 1.2+)
+ * mac_id id of hash function for HMAC
+ * bc_impl block cipher implementation (CBC encryption)
+ * cipher_key_len block cipher key length (in bytes)
+ */
+void br_ssl_engine_switch_cbc_out(br_ssl_engine_context *cc,
+ int is_client, int prf_id, int mac_id,
+ const br_block_cbcenc_class *bc_impl, size_t cipher_key_len);
+
+/*
+ * Switch to GCM decryption for incoming records.
+ * cc the engine context
+ * is_client non-zero for a client, zero for a server
+ * prf_id id of hash function for PRF
+ * bc_impl block cipher implementation (CTR)
+ * cipher_key_len block cipher key length (in bytes)
+ */
+void br_ssl_engine_switch_gcm_in(br_ssl_engine_context *cc,
+ int is_client, int prf_id,
+ const br_block_ctr_class *bc_impl, size_t cipher_key_len);
+
+/*
+ * Switch to GCM encryption for outgoing records.
+ * cc the engine context
+ * is_client non-zero for a client, zero for a server
+ * prf_id id of hash function for PRF
+ * bc_impl block cipher implementation (CTR)
+ * cipher_key_len block cipher key length (in bytes)
+ */
+void br_ssl_engine_switch_gcm_out(br_ssl_engine_context *cc,
+ int is_client, int prf_id,
+ const br_block_ctr_class *bc_impl, size_t cipher_key_len);
+
+/*
+ * Calls to T0-generated code.
+ */
+void br_ssl_hs_client_init_main(void *ctx);
+void br_ssl_hs_client_run(void *ctx);
+void br_ssl_hs_server_init_main(void *ctx);
+void br_ssl_hs_server_run(void *ctx);
+
+/*
+ * Get the hash function to use for signatures, given a bit mask of
+ * supported hash functions. This implements a strict choice order
+ * (namely SHA-256, SHA-384, SHA-512, SHA-224, SHA-1). If the mask
+ * does not document support of any of these hash functions, then this
+ * functions returns 0.
+ */
+int br_ssl_choose_hash(unsigned bf);
+
+/* ==================================================================== */
+
+#endif
--- /dev/null
+/*
+ * 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 inner.h */
+uint32_t
+br_i31_add(uint32_t *a, const uint32_t *b, uint32_t ctl)
+{
+ uint32_t cc;
+ size_t u, m;
+
+ cc = 0;
+ m = (a[0] + 63) >> 5;
+ for (u = 1; u < m; u ++) {
+ uint32_t aw, bw, naw;
+
+ aw = a[u];
+ bw = b[u];
+ naw = aw + bw + cc;
+ cc = naw >> 31;
+ a[u] = MUX(ctl, naw & (uint32_t)0x7FFFFFFF, aw);
+ }
+ return cc;
+}
--- /dev/null
+/*
+ * 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 inner.h */
+uint32_t
+br_i31_bit_length(uint32_t *x, size_t xlen)
+{
+ uint32_t tw, twk;
+
+ tw = 0;
+ twk = 0;
+ while (xlen -- > 0) {
+ uint32_t w, c;
+
+ c = EQ(tw, 0);
+ w = x[xlen];
+ tw = MUX(c, w, tw);
+ twk = MUX(c, (uint32_t)xlen, twk);
+ }
+ return (twk << 5) + BIT_LENGTH(tw);
+}
--- /dev/null
+/*
+ * 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 inner.h */
+uint32_t
+br_i31_decode_mod(uint32_t *x, const void *src, size_t len, const uint32_t *m)
+{
+ /*
+ * Two-pass algorithm: in the first pass, we determine whether the
+ * value fits; in the second pass, we do the actual write.
+ *
+ * During the first pass, 'r' contains the comparison result so
+ * far:
+ * 0x00000000 value is equal to the modulus
+ * 0x00000001 value is greater than the modulus
+ * 0xFFFFFFFF value is lower than the modulus
+ *
+ * Since we iterate starting with the least significant bytes (at
+ * the end of src[]), each new comparison overrides the previous
+ * except when the comparison yields 0 (equal).
+ *
+ * During the second pass, 'r' is either 0xFFFFFFFF (value fits)
+ * or 0x00000000 (value does not fit).
+ *
+ * We must iterate over all bytes of the source, _and_ possibly
+ * some extra virutal bytes (with value 0) so as to cover the
+ * complete modulus as well. We also add 4 such extra bytes beyond
+ * the modulus length because it then guarantees that no accumulated
+ * partial word remains to be processed.
+ */
+ const unsigned char *buf;
+ size_t mlen, tlen;
+ int pass;
+ uint32_t r;
+
+ buf = src;
+ mlen = (m[0] + 31) >> 5;
+ tlen = (mlen << 2);
+ if (tlen < len) {
+ tlen = len;
+ }
+ tlen += 4;
+ r = 0;
+ for (pass = 0; pass < 2; pass ++) {
+ size_t u, v;
+ uint32_t acc;
+ int acc_len;
+
+ v = 1;
+ acc = 0;
+ acc_len = 0;
+ for (u = 0; u < tlen; u ++) {
+ uint32_t b;
+
+ if (u < len) {
+ b = buf[len - 1 - u];
+ } else {
+ b = 0;
+ }
+ acc |= (b << acc_len);
+ acc_len += 8;
+ if (acc_len >= 31) {
+ uint32_t xw;
+
+ xw = acc & (uint32_t)0x7FFFFFFF;
+ acc_len -= 31;
+ acc = b >> (8 - acc_len);
+ if (v <= mlen) {
+ if (pass) {
+ x[v] = r & xw;
+ } else {
+ uint32_t cc;
+
+ cc = (uint32_t)CMP(xw, m[v]);
+ r = MUX(EQ(cc, 0), r, cc);
+ }
+ } else {
+ if (!pass) {
+ r = MUX(EQ(xw, 0), r, 1);
+ }
+ }
+ v ++;
+ }
+ }
+
+ /*
+ * When we reach this point at the end of the first pass:
+ * r is either 0, 1 or -1; we want to set r to 0 if it
+ * is equal to 0 or 1, and leave it to -1 otherwise.
+ *
+ * When we reach this point at the end of the second pass:
+ * r is either 0 or -1; we want to leave that value
+ * untouched. This is a subcase of the previous.
+ */
+ r >>= 1;
+ r |= (r << 1);
+ }
+
+ x[0] = m[0];
+ return r & (uint32_t)1;
+}
--- /dev/null
+/*
+ * 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 inner.h */
+void
+br_i31_decode(uint32_t *x, const void *src, size_t len)
+{
+ const unsigned char *buf;
+ size_t u, v;
+ uint32_t acc;
+ int acc_len;
+
+ buf = src;
+ u = len;
+ v = 1;
+ acc = 0;
+ acc_len = 0;
+ while (u -- > 0) {
+ uint32_t b;
+
+ b = buf[u];
+ acc |= (b << acc_len);
+ acc_len += 8;
+ if (acc_len >= 31) {
+ x[v ++] = acc & (uint32_t)0x7FFFFFFF;
+ acc_len -= 31;
+ acc = b >> (8 - acc_len);
+ }
+ }
+ if (acc_len != 0) {
+ x[v ++] = acc;
+ }
+ x[0] = br_i31_bit_length(x + 1, v - 1);
+}
--- /dev/null
+/*
+ * 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 inner.h */
+void
+br_i31_decode_reduce(uint32_t *x,
+ const void *src, size_t len, const uint32_t *m)
+{
+ uint32_t m_ebitlen, m_rbitlen;
+ size_t mblen, k;
+ const unsigned char *buf;
+ uint32_t acc;
+ int acc_len;
+
+ /*
+ * Get the encoded bit length.
+ */
+ m_ebitlen = m[0];
+
+ /*
+ * Special case for an invalid (null) modulus.
+ */
+ if (m_ebitlen == 0) {
+ x[0] = 0;
+ return;
+ }
+
+ /*
+ * Clear the destination.
+ */
+ br_i31_zero(x, m_ebitlen);
+
+ /*
+ * First decode directly as many bytes as possible. This requires
+ * computing the actual bit length.
+ */
+ m_rbitlen = m_ebitlen >> 5;
+ m_rbitlen = (m_ebitlen & 31) + (m_rbitlen << 5) - m_rbitlen;
+ mblen = (m_rbitlen + 7) >> 3;
+ k = mblen - 1;
+ if (k >= len) {
+ br_i31_decode(x, src, len);
+ x[0] = m_ebitlen;
+ return;
+ }
+ buf = src;
+ br_i31_decode(x, buf, k);
+ x[0] = m_ebitlen;
+
+ /*
+ * Input remaining bytes, using 31-bit words.
+ */
+ acc = 0;
+ acc_len = 0;
+ while (k < len) {
+ uint32_t v;
+
+ v = buf[k ++];
+ if (acc_len >= 23) {
+ acc_len -= 23;
+ acc <<= (8 - acc_len);
+ acc |= v >> acc_len;
+ br_i31_muladd_small(x, acc, m);
+ acc = v & (0xFF >> (8 - acc_len));
+ } else {
+ acc = (acc << 8) | v;
+ acc_len += 8;
+ }
+ }
+
+ /*
+ * We may have some bits accumulated. We then perform a shift to
+ * be able to inject these bits as a full 31-bit word.
+ */
+ if (acc_len != 0) {
+ acc = (acc | (x[1] << acc_len)) & 0x7FFFFFFF;
+ br_i31_rshift(x, 31 - acc_len);
+ br_i31_muladd_small(x, acc, m);
+ }
+}
--- /dev/null
+/*
+ * 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 inner.h */
+void
+br_i31_encode(void *dst, size_t len, const uint32_t *x)
+{
+ unsigned char *buf;
+ size_t k, xlen;
+ uint32_t acc;
+ int acc_len;
+
+ xlen = (x[0] + 31) >> 5;
+ if (xlen == 0) {
+ memset(dst, 0, len);
+ return;
+ }
+ buf = (unsigned char *)dst + len;
+ k = 1;
+ acc = 0;
+ acc_len = 0;
+ while (len != 0) {
+ uint32_t w;
+
+ w = (k <= xlen) ? x[k] : 0;
+ k ++;
+ if (acc_len == 0) {
+ acc = w;
+ acc_len = 31;
+ } else {
+ uint32_t z;
+
+ z = acc | (w << acc_len);
+ acc_len --;
+ acc = w >> (31 - acc_len);
+ if (len >= 4) {
+ buf -= 4;
+ len -= 4;
+ br_enc32be(buf, z);
+ } else {
+ switch (len) {
+ case 3:
+ buf[-3] = (unsigned char)(z >> 16);
+ /* fall through */
+ case 2:
+ buf[-2] = (unsigned char)(z >> 8);
+ /* fall through */
+ case 1:
+ buf[-1] = (unsigned char)z;
+ break;
+ }
+ return;
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * 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 inner.h */
+void
+br_i31_from_monty(uint32_t *x, const uint32_t *m, uint32_t m0i)
+{
+ size_t len, u, v;
+
+ len = (m[0] + 31) >> 5;
+ for (u = 0; u < len; u ++) {
+ uint32_t f;
+ uint64_t cc;
+
+ f = (x[1] * m0i) & 0x7FFFFFFF;
+ cc = 0;
+ for (v = 0; v < len; v ++) {
+ uint64_t z;
+
+ z = (uint64_t)x[v + 1] + MUL31(f, m[v + 1]) + cc;
+ cc = z >> 31;
+ if (v != 0) {
+ x[v] = (uint32_t)z & 0x7FFFFFFF;
+ }
+ }
+ x[len] = (uint32_t)cc;
+ }
+
+ /*
+ * We may have to do an extra subtraction, but only if the
+ * value in x[] is indeed greater than or equal to that of m[],
+ * which is why we must do two calls (first call computes the
+ * carry, second call performs the subtraction only if the carry
+ * is 0).
+ */
+ br_i31_sub(x, m, NOT(br_i31_sub(x, m, 0)));
+}
--- /dev/null
+/*
+ * 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 inner.h */
+uint32_t
+br_i31_iszero(const uint32_t *x)
+{
+ uint32_t z;
+ size_t u;
+
+ z = 0;
+ for (u = (x[0] + 31) >> 5; u > 0; u --) {
+ z |= x[u];
+ }
+ return ~(z | -z) >> 31;
+}
--- /dev/null
+/*
+ * 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 inner.h */
+void
+br_i31_modpow(uint32_t *x,
+ const unsigned char *e, size_t elen,
+ const uint32_t *m, uint32_t m0i, uint32_t *t1, uint32_t *t2)
+{
+ size_t mlen;
+ uint32_t k;
+
+ /*
+ * 'mlen' is the length of m[] expressed in bytes (including
+ * the "bit length" first field).
+ */
+ mlen = ((m[0] + 63) >> 5) * sizeof m[0];
+
+ /*
+ * Throughout the algorithm:
+ * -- t1[] is in Montgomery representation; it contains x, x^2,
+ * x^4, x^8...
+ * -- The result is accumulated, in normal representation, in
+ * the x[] array.
+ * -- t2[] is used as destination buffer for each multiplication.
+ *
+ * Note that there is no need to call br_i32_from_monty().
+ */
+ memcpy(t1, x, mlen);
+ br_i31_to_monty(t1, m);
+ br_i31_zero(x, m[0]);
+ x[1] = 1;
+ for (k = 0; k < ((uint32_t)elen << 3); k ++) {
+ uint32_t ctl;
+
+ ctl = (e[elen - 1 - (k >> 3)] >> (k & 7)) & 1;
+ br_i31_montymul(t2, x, t1, m, m0i);
+ CCOPY(ctl, x, t2, mlen);
+ br_i31_montymul(t2, t1, t1, m, m0i);
+ memcpy(t1, t2, mlen);
+ }
+}
--- /dev/null
+/*
+ * 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 inner.h */
+void
+br_i31_montymul(uint32_t *d, const uint32_t *x, const uint32_t *y,
+ const uint32_t *m, uint32_t m0i)
+{
+ size_t len, len4, u, v;
+ uint64_t dh;
+
+ len = (m[0] + 31) >> 5;
+ len4 = len & ~(size_t)3;
+ br_i32_zero(d, m[0]);
+ dh = 0;
+ for (u = 0; u < len; u ++) {
+ uint32_t f, xu;
+ uint64_t r, zh;
+
+ xu = x[u + 1];
+ f = ((d[1] + x[u + 1] * y[1]) * m0i) & 0x7FFFFFFF;
+
+ r = 0;
+ for (v = 0; v < len4; v += 4) {
+ uint64_t z;
+
+ z = (uint64_t)d[v + 1] + MUL31(xu, y[v + 1])
+ + MUL31(f, m[v + 1]) + r;
+ r = z >> 31;
+ d[v + 0] = (uint32_t)z & 0x7FFFFFFF;
+ z = (uint64_t)d[v + 2] + MUL31(xu, y[v + 2])
+ + MUL31(f, m[v + 2]) + r;
+ r = z >> 31;
+ d[v + 1] = (uint32_t)z & 0x7FFFFFFF;
+ z = (uint64_t)d[v + 3] + MUL31(xu, y[v + 3])
+ + MUL31(f, m[v + 3]) + r;
+ r = z >> 31;
+ d[v + 2] = (uint32_t)z & 0x7FFFFFFF;
+ z = (uint64_t)d[v + 4] + MUL31(xu, y[v + 4])
+ + MUL31(f, m[v + 4]) + r;
+ r = z >> 31;
+ d[v + 3] = (uint32_t)z & 0x7FFFFFFF;
+ }
+ for (; v < len; v ++) {
+ uint64_t z;
+
+ z = (uint64_t)d[v + 1] + MUL31(xu, y[v + 1])
+ + MUL31(f, m[v + 1]) + r;
+ r = z >> 31;
+ d[v] = (uint32_t)z & 0x7FFFFFFF;
+ }
+
+ zh = dh + r;
+ d[len] = (uint32_t)zh & 0x7FFFFFFF;
+ dh = zh >> 31;
+ }
+
+ /*
+ * We must write back the bit length because it was overwritten in
+ * the loop (not overwriting it would require a test in the loop,
+ * which would yield bigger and slower code).
+ */
+ d[0] = m[0];
+
+ /*
+ * d[] may still be greater than m[] at that point; notably, the
+ * 'dh' word may be non-zero.
+ */
+ br_i31_sub(d, m, NEQ(dh, 0) | NOT(br_i31_sub(d, m, 0)));
+}
--- /dev/null
+/*
+ * 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 inner.h */
+void
+br_i31_mulacc(uint32_t *d, const uint32_t *a, const uint32_t *b)
+{
+ size_t alen, blen, u;
+
+ alen = (a[0] + 31) >> 5;
+ blen = (b[0] + 31) >> 5;
+ d[0] = a[0] + b[0];
+ for (u = 0; u < blen; u ++) {
+ uint32_t f;
+ size_t v;
+ uint64_t cc;
+
+ f = b[1 + u];
+ cc = 0;
+ for (v = 0; v < alen; v ++) {
+ uint64_t z;
+
+ z = (uint64_t)d[1 + u + v] + MUL31(f, a[1 + v]) + cc;
+ cc = z >> 31;
+ d[1 + u + v] = (uint32_t)z & 0x7FFFFFFF;
+ }
+ d[1 + u + alen] = (uint32_t)cc;
+ }
+}
--- /dev/null
+/*
+ * 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 inner.h */
+void
+br_i31_muladd_small(uint32_t *x, uint32_t z, const uint32_t *m)
+{
+ uint32_t m_bitlen;
+ unsigned mblr;
+ size_t u, mlen;
+ uint32_t a0, a1, b0, hi, g, q, tb;
+ uint32_t under, over;
+ uint32_t cc;
+
+ /*
+ * We can test on the modulus bit length since we accept to
+ * leak that length.
+ */
+ m_bitlen = m[0];
+ if (m_bitlen == 0) {
+ return;
+ }
+ if (m_bitlen <= 31) {
+ uint32_t hi, lo;
+
+ hi = x[1] >> 1;
+ lo = (x[1] << 31) | z;
+ x[1] = br_rem(hi, lo, m[1]);
+ return;
+ }
+ mlen = (m_bitlen + 31) >> 5;
+ mblr = (unsigned)m_bitlen & 31;
+
+ /*
+ * Principle: we estimate the quotient (x*2^31+z)/m by
+ * doing a 64/32 division with the high words.
+ *
+ * Let:
+ * w = 2^31
+ * a = (w*a0 + a1) * w^N + a2
+ * b = b0 * w^N + b2
+ * such that:
+ * 0 <= a0 < w
+ * 0 <= a1 < w
+ * 0 <= a2 < w^N
+ * w/2 <= b0 < w
+ * 0 <= b2 < w^N
+ * a < w*b
+ * I.e. the two top words of a are a0:a1, the top word of b is
+ * b0, we ensured that b0 is "full" (high bit set), and a is
+ * such that the quotient q = a/b fits on one word (0 <= q < w).
+ *
+ * If a = b*q + r (with 0 <= r < q), we can estimate q by
+ * doing an Euclidean division on the top words:
+ * a0*w+a1 = b0*u + v (with 0 <= v < w)
+ * Then the following holds:
+ * 0 <= u <= w
+ * u-2 <= q <= u
+ */
+ hi = x[mlen];
+ if (mblr == 0) {
+ a0 = x[mlen];
+ memmove(x + 2, x + 1, (mlen - 1) * sizeof *x);
+ x[1] = z;
+ a1 = x[mlen];
+ b0 = m[mlen];
+ } else {
+ a0 = ((x[mlen] << (31 - mblr)) | (x[mlen - 1] >> mblr))
+ & 0x7FFFFFFF;
+ memmove(x + 2, x + 1, (mlen - 1) * sizeof *x);
+ x[1] = z;
+ a1 = ((x[mlen] << (31 - mblr)) | (x[mlen - 1] >> mblr))
+ & 0x7FFFFFFF;
+ b0 = ((m[mlen] << (31 - mblr)) | (m[mlen - 1] >> mblr))
+ & 0x7FFFFFFF;
+ }
+
+ /*
+ * We estimate a divisor q. If the quotient returned by br_div()
+ * is g:
+ * -- If a0 == b0 then g == 0; we want q = 0x7FFFFFFF.
+ * -- Otherwise:
+ * -- if g == 0 then we set q = 0;
+ * -- otherwise, we set q = g - 1.
+ * The properties described above then ensure that the true
+ * quotient is q-1, q or q+1.
+ *
+ * Take care that a0, a1 and b0 are 31-bit words, not 32-bit. We
+ * must adjust the parameters to br_div() accordingly.
+ */
+ g = br_div(a0 >> 1, a1 | (a0 << 31), b0);
+ q = MUX(EQ(a0, b0), 0x7FFFFFFF, MUX(EQ(g, 0), 0, g - 1));
+
+ /*
+ * We subtract q*m from x (with the extra high word of value 'hi').
+ * Since q may be off by 1 (in either direction), we may have to
+ * add or subtract m afterwards.
+ *
+ * The 'tb' flag will be true (1) at the end of the loop if the
+ * result is greater than or equal to the modulus (not counting
+ * 'hi' or the carry).
+ */
+ cc = 0;
+ tb = 1;
+ for (u = 1; u <= mlen; u ++) {
+ uint32_t mw, zw, xw, nxw;
+ uint64_t zl;
+
+ mw = m[u];
+ zl = MUL31(mw, q) + cc;
+ cc = (uint32_t)(zl >> 31);
+ zw = (uint32_t)zl & (uint32_t)0x7FFFFFFF;
+ xw = x[u];
+ nxw = xw - zw;
+ cc += nxw >> 31;
+ nxw &= 0x7FFFFFFF;
+ x[u] = nxw;
+ tb = MUX(EQ(nxw, mw), tb, GT(nxw, mw));
+ }
+
+ /*
+ * If we underestimated q, then either cc < hi (one extra bit
+ * beyond the top array word), or cc == hi and tb is true (no
+ * extra bit, but the result is not lower than the modulus). In
+ * these cases we must subtract m once.
+ *
+ * Otherwise, we may have overestimated, which will show as
+ * cc > hi (thus a negative result). Correction is adding m once.
+ */
+ over = GT(cc, hi);
+ under = ~over & (tb | LT(cc, hi));
+ br_i31_add(x, m, over);
+ br_i31_sub(x, m, under);
+}
--- /dev/null
+/*
+ * 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 inner.h */
+uint32_t
+br_i31_ninv31(uint32_t x)
+{
+ uint32_t y;
+
+ y = 2 - x;
+ y *= 2 - y * x;
+ y *= 2 - y * x;
+ y *= 2 - y * x;
+ y *= 2 - y * x;
+ return MUX(x & 1, -y, 0) & 0x7FFFFFFF;
+}
--- /dev/null
+/*
+ * 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 inner.h */
+void
+br_i31_reduce(uint32_t *x, const uint32_t *a, const uint32_t *m)
+{
+ uint32_t m_bitlen, a_bitlen;
+ size_t mlen, alen, u;
+
+ m_bitlen = m[0];
+ mlen = (m_bitlen + 31) >> 5;
+
+ x[0] = m_bitlen;
+ if (m_bitlen == 0) {
+ return;
+ }
+
+ /*
+ * If the source is shorter, then simply copy all words from a[]
+ * and zero out the upper words.
+ */
+ a_bitlen = a[0];
+ alen = (a_bitlen + 31) >> 5;
+ if (a_bitlen < m_bitlen) {
+ memcpy(x + 1, a + 1, alen * sizeof *a);
+ for (u = alen; u < mlen; u ++) {
+ x[u + 1] = 0;
+ }
+ return;
+ }
+
+ /*
+ * The source length is at least equal to that of the modulus.
+ * We must thus copy N-1 words, and input the remaining words
+ * one by one.
+ */
+ memcpy(x + 1, a + 2 + (alen - mlen), (mlen - 1) * sizeof *a);
+ x[mlen] = 0;
+ for (u = 1 + alen - mlen; u > 0; u --) {
+ br_i31_muladd_small(x, a[u], m);
+ }
+}
--- /dev/null
+/*
+ * 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 inner.h */
+void
+br_i31_rshift(uint32_t *x, int count)
+{
+ size_t u, len;
+ uint32_t r;
+
+ len = (x[0] + 31) >> 5;
+ if (len == 0) {
+ return;
+ }
+ r = x[1] >> count;
+ for (u = 2; u <= len; u ++) {
+ uint32_t w;
+
+ w = x[u];
+ x[u - 1] = ((w << (31 - count)) | r) & 0x7FFFFFFF;
+ r = w >> count;
+ }
+ x[len] = r;
+}
--- /dev/null
+/*
+ * 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 inner.h */
+uint32_t
+br_i31_sub(uint32_t *a, const uint32_t *b, uint32_t ctl)
+{
+ uint32_t cc;
+ size_t u, m;
+
+ cc = 0;
+ m = (a[0] + 63) >> 5;
+ for (u = 1; u < m; u ++) {
+ uint32_t aw, bw, naw;
+
+ aw = a[u];
+ bw = b[u];
+ naw = aw - bw - cc;
+ cc = naw >> 31;
+ a[u] = MUX(ctl, naw & 0x7FFFFFFF, aw);
+ }
+ return cc;
+}
--- /dev/null
+/*
+ * 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 inner.h */
+void
+br_i31_to_monty(uint32_t *x, const uint32_t *m)
+{
+ uint32_t k;
+
+ for (k = (m[0] + 31) >> 5; k > 0; k --) {
+ br_i31_muladd_small(x, 0, m);
+ }
+}
--- /dev/null
+/*
+ * 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 inner.h */
+uint32_t
+br_i32_add(uint32_t *a, const uint32_t *b, uint32_t ctl)
+{
+ uint32_t cc;
+ size_t u, m;
+
+ cc = 0;
+ m = (a[0] + 63) >> 5;
+ for (u = 1; u < m; u ++) {
+ uint32_t aw, bw, naw;
+
+ aw = a[u];
+ bw = b[u];
+ naw = aw + bw + cc;
+
+ /*
+ * Carry is 1 if naw < aw. Carry is also 1 if naw == aw
+ * AND the carry was already 1.
+ */
+ cc = (cc & EQ(naw, aw)) | LT(naw, aw);
+ a[u] = MUX(ctl, naw, aw);
+ }
+ return cc;
+}
--- /dev/null
+/*
+ * 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 inner.h */
+uint32_t
+br_i32_bit_length(uint32_t *x, size_t xlen)
+{
+ uint32_t tw, twk;
+
+ tw = 0;
+ twk = 0;
+ while (xlen -- > 0) {
+ uint32_t w, c;
+
+ c = EQ(tw, 0);
+ w = x[xlen];
+ tw = MUX(c, w, tw);
+ twk = MUX(c, (uint32_t)xlen, twk);
+ }
+ return (twk << 5) + BIT_LENGTH(tw);
+}
--- /dev/null
+/*
+ * 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 inner.h */
+uint32_t
+br_i32_decode_mod(uint32_t *x, const void *src, size_t len, const uint32_t *m)
+{
+ const unsigned char *buf;
+ uint32_t r;
+ size_t u, v, mlen;
+
+ buf = src;
+
+ /*
+ * First pass: determine whether the value fits. The 'r' value
+ * will contain the comparison result, as 0x00000000 (value is
+ * equal to the modulus), 0x00000001 (value is greater than the
+ * modulus), or 0xFFFFFFFF (value is lower than the modulus).
+ */
+ mlen = (m[0] + 7) >> 3;
+ r = 0;
+ for (u = (mlen > len) ? mlen : len; u > 0; u --) {
+ uint32_t mb, xb;
+
+ v = u - 1;
+ if (v >= mlen) {
+ mb = 0;
+ } else {
+ mb = (m[1 + (v >> 2)] >> ((v & 3) << 3)) & 0xFF;
+ }
+ if (v >= len) {
+ xb = 0;
+ } else {
+ xb = buf[len - u];
+ }
+ r = MUX(EQ(r, 0), (uint32_t)CMP(xb, mb), r);
+ }
+
+ /*
+ * Only r == 0xFFFFFFFF is acceptable. We want to set r to 0xFF if
+ * the value fits, 0x00 otherwise.
+ */
+ r >>= 24;
+ br_i32_zero(x, m[0]);
+ u = (mlen > len) ? len : mlen;
+ while (u > 0) {
+ uint32_t xb;
+
+ xb = buf[len - u] & r;
+ u --;
+ x[1 + (u >> 2)] |= xb << ((u & 3) << 3);
+ }
+ return r >> 7;
+}
--- /dev/null
+/*
+ * 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 inner.h */
+void
+br_i32_decode(uint32_t *x, const void *src, size_t len)
+{
+ const unsigned char *buf;
+ size_t u, v;
+
+ buf = src;
+ u = len;
+ v = 1;
+ for (;;) {
+ if (u < 4) {
+ uint32_t w;
+
+ if (u < 2) {
+ if (u == 0) {
+ break;
+ } else {
+ w = buf[0];
+ }
+ } else {
+ if (u == 2) {
+ w = br_dec16be(buf);
+ } else {
+ w = ((uint32_t)buf[0] << 16)
+ | br_dec16be(buf + 1);
+ }
+ }
+ x[v ++] = w;
+ break;
+ } else {
+ u -= 4;
+ x[v ++] = br_dec32be(buf + u);
+ }
+ }
+ x[0] = br_i32_bit_length(x + 1, v - 1);
+}
--- /dev/null
+/*
+ * 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 inner.h */
+void
+br_i32_decode_reduce(uint32_t *x,
+ const void *src, size_t len, const uint32_t *m)
+{
+ uint32_t m_bitlen;
+ size_t mblen, k, q;
+ const unsigned char *buf;
+
+ m_bitlen = m[0];
+
+ /*
+ * Special case for an invalid modulus.
+ */
+ if (m_bitlen == 0) {
+ x[0] = 0;
+ return;
+ }
+
+ /*
+ * Clear the destination.
+ */
+ br_i32_zero(x, m_bitlen);
+
+ /*
+ * First decode directly as many bytes as possible without
+ * reduction, taking care to leave a number of bytes which
+ * is a multiple of 4.
+ */
+ mblen = (m_bitlen + 7) >> 3;
+ k = mblen - 1;
+
+ /*
+ * Up to k bytes can be safely decoded.
+ */
+ if (k >= len) {
+ br_i32_decode(x, src, len);
+ x[0] = m_bitlen;
+ return;
+ }
+
+ /*
+ * We want to first inject some bytes with direct decoding,
+ * then extra bytes by whole 32-bit words. First compute
+ * the size that should be injected that way.
+ */
+ buf = src;
+ q = (len - k + 3) & ~(size_t)3;
+
+ /*
+ * It may happen that this is more than what we already have
+ * (by at most 3 bytes). Such a case may happen only with
+ * a very short modulus. In that case, we must process the first
+ * bytes "manually".
+ */
+ if (q > len) {
+ int i;
+ uint32_t w;
+
+ w = 0;
+ for (i = 0; i < 4; i ++) {
+ w <<= 8;
+ if (q <= len) {
+ w |= buf[len - q];
+ }
+ q --;
+ }
+ br_i32_muladd_small(x, w, m);
+ } else {
+ br_i32_decode(x, buf, len - q);
+ x[0] = m_bitlen;
+ }
+
+ /*
+ * At that point, we have exactly q bytes to inject, and q is
+ * a multiple of 4.
+ */
+ for (k = len - q; k < len; k += 4) {
+ br_i32_muladd_small(x, br_dec32be(buf + k), m);
+ }
+}
--- /dev/null
+/*
+ * 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 inner.h */
+uint32_t
+br_divrem(uint32_t hi, uint32_t lo, uint32_t d, uint32_t *r)
+{
+ // TODO: optimize this
+ uint32_t q;
+ uint32_t ch, cf;
+ int k;
+
+ q = 0;
+ ch = EQ(hi, d);
+ hi = MUX(ch, 0, hi);
+ for (k = 31; k > 0; k --) {
+ int j;
+ uint32_t w, ctl, hi2, lo2;
+
+ j = 32 - k;
+ w = (hi << j) | (lo >> k);
+ ctl = GE(w, d) | (hi >> k);
+ hi2 = (w - d) >> j;
+ lo2 = lo - (d << k);
+ hi = MUX(ctl, hi2, hi);
+ lo = MUX(ctl, lo2, lo);
+ q |= ctl << k;
+ }
+ cf = GE(lo, d) | hi;
+ q |= cf;
+ *r = MUX(cf, lo - d, lo);
+ return q;
+}
--- /dev/null
+/*
+ * 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 inner.h */
+void
+br_i32_encode(void *dst, size_t len, const uint32_t *x)
+{
+ unsigned char *buf;
+ size_t k;
+
+ buf = dst;
+
+ /*
+ * Compute the announced size of x in bytes; extra bytes are
+ * filled with zeros.
+ */
+ k = (x[0] + 7) >> 3;
+ while (len > k) {
+ *buf ++ = 0;
+ len --;
+ }
+
+ /*
+ * Now we use k as index within x[]. That index starts at 1;
+ * we initialize it to the topmost complete word, and process
+ * any remaining incomplete word.
+ */
+ k = (len + 3) >> 2;
+ switch (len & 3) {
+ case 3:
+ *buf ++ = x[k] >> 16;
+ /* fall through */
+ case 2:
+ *buf ++ = x[k] >> 8;
+ /* fall through */
+ case 1:
+ *buf ++ = x[k];
+ k --;
+ }
+
+ /*
+ * Encode all complete words.
+ */
+ while (k > 0) {
+ br_enc32be(buf, x[k]);
+ k --;
+ buf += 4;
+ }
+}
--- /dev/null
+/*
+ * 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 inner.h */
+void
+br_i32_from_monty(uint32_t *x, const uint32_t *m, uint32_t m0i)
+{
+ size_t len, u, v;
+
+ len = (m[0] + 31) >> 5;
+ for (u = 0; u < len; u ++) {
+ uint32_t f;
+ uint64_t cc;
+
+ f = x[1] * m0i;
+ cc = 0;
+ for (v = 0; v < len; v ++) {
+ uint64_t z;
+
+ z = (uint64_t)x[v + 1] + MUL(f, m[v + 1]) + cc;
+ cc = z >> 32;
+ if (v != 0) {
+ x[v] = (uint32_t)z;
+ }
+ }
+ x[len] = (uint32_t)cc;
+ }
+
+ /*
+ * We may have to do an extra subtraction, but only if the
+ * value in x[] is indeed greater than or equal to that of m[],
+ * which is why we must do two calls (first call computes the
+ * carry, second call performs the subtraction only if the carry
+ * is 0).
+ */
+ br_i32_sub(x, m, NOT(br_i32_sub(x, m, 0)));
+}
--- /dev/null
+/*
+ * 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 inner.h */
+uint32_t
+br_i32_iszero(const uint32_t *x)
+{
+ uint32_t z;
+ size_t u;
+
+ z = 0;
+ for (u = (x[0] + 31) >> 5; u > 0; u --) {
+ z |= x[u];
+ }
+ return ~(z | -z) >> 31;
+}
--- /dev/null
+/*
+ * 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 inner.h */
+void
+br_i32_modpow(uint32_t *x,
+ const unsigned char *e, size_t elen,
+ const uint32_t *m, uint32_t m0i, uint32_t *t1, uint32_t *t2)
+{
+ size_t mlen;
+ uint32_t k;
+
+ /*
+ * 'mlen' is the length of m[] expressed in bytes (including
+ * the "bit length" first field).
+ */
+ mlen = ((m[0] + 63) >> 5) * sizeof m[0];
+
+ /*
+ * Throughout the algorithm:
+ * -- t1[] is in Montgomery representation; it contains x, x^2,
+ * x^4, x^8...
+ * -- The result is accumulated, in normal representation, in
+ * the x[] array.
+ * -- t2[] is used as destination buffer for each multiplication.
+ *
+ * Note that there is no need to call br_i32_from_monty().
+ */
+ memcpy(t1, x, mlen);
+ br_i32_to_monty(t1, m);
+ br_i32_zero(x, m[0]);
+ x[1] = 1;
+ for (k = 0; k < ((uint32_t)elen << 3); k ++) {
+ uint32_t ctl;
+
+ ctl = (e[elen - 1 - (k >> 3)] >> (k & 7)) & 1;
+ br_i32_montymul(t2, x, t1, m, m0i);
+ CCOPY(ctl, x, t2, mlen);
+ br_i32_montymul(t2, t1, t1, m, m0i);
+ memcpy(t1, t2, mlen);
+ }
+}
--- /dev/null
+/*
+ * 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 inner.h */
+void
+br_i32_montymul(uint32_t *d, const uint32_t *x, const uint32_t *y,
+ const uint32_t *m, uint32_t m0i)
+{
+ size_t len, u, v;
+ uint64_t dh;
+
+ len = (m[0] + 31) >> 5;
+ br_i32_zero(d, m[0]);
+ dh = 0;
+ for (u = 0; u < len; u ++) {
+ uint32_t f, xu;
+ uint64_t r1, r2, zh;
+
+ xu = x[u + 1];
+ f = (d[1] + x[u + 1] * y[1]) * m0i;
+ r1 = 0;
+ r2 = 0;
+ for (v = 0; v < len; v ++) {
+ uint64_t z;
+ uint32_t t;
+
+ z = (uint64_t)d[v + 1] + MUL(xu, y[v + 1]) + r1;
+ r1 = z >> 32;
+ t = (uint32_t)z;
+ z = (uint64_t)t + MUL(f, m[v + 1]) + r2;
+ r2 = z >> 32;
+ if (v != 0) {
+ d[v] = (uint32_t)z;
+ }
+ }
+ zh = dh + r1 + r2;
+ d[len] = (uint32_t)zh;
+ dh = zh >> 32;
+ }
+
+ /*
+ * d[] may still be greater than m[] at that point; notably, the
+ * 'dh' word may be non-zero.
+ */
+ br_i32_sub(d, m, NEQ(dh, 0) | NOT(br_i32_sub(d, m, 0)));
+}
--- /dev/null
+/*
+ * 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 inner.h */
+void
+br_i32_mulacc(uint32_t *d, const uint32_t *a, const uint32_t *b)
+{
+ size_t alen, blen, u;
+
+ alen = (a[0] + 31) >> 5;
+ blen = (b[0] + 31) >> 5;
+ d[0] = a[0] + b[0];
+ for (u = 0; u < blen; u ++) {
+ uint32_t f;
+ size_t v;
+ uint64_t cc;
+
+ f = b[1 + u];
+ cc = 0;
+ for (v = 0; v < alen; v ++) {
+ uint64_t z;
+
+ z = (uint64_t)d[1 + u + v] + MUL(f, a[1 + v]) + cc;
+ cc = z >> 32;
+ d[1 + u + v] = (uint32_t)z;
+ }
+ d[1 + u + alen] = (uint32_t)cc;
+ }
+}
--- /dev/null
+/*
+ * 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 inner.h */
+void
+br_i32_muladd_small(uint32_t *x, uint32_t z, const uint32_t *m)
+{
+ uint32_t m_bitlen;
+ size_t u, mlen;
+ uint32_t a0, a1, b0, hi, g, q, tb;
+ uint32_t chf, clow, under, over;
+ uint64_t cc;
+
+ /*
+ * We can test on the modulus bit length since we accept to
+ * leak that length.
+ */
+ m_bitlen = m[0];
+ if (m_bitlen == 0) {
+ return;
+ }
+ if (m_bitlen <= 32) {
+ x[1] = br_rem(x[1], z, m[1]);
+ return;
+ }
+ mlen = (m_bitlen + 31) >> 5;
+
+ /*
+ * Principle: we estimate the quotient (x*2^32+z)/m by
+ * doing a 64/32 division with the high words.
+ *
+ * Let:
+ * w = 2^32
+ * a = (w*a0 + a1) * w^N + a2
+ * b = b0 * w^N + b2
+ * such that:
+ * 0 <= a0 < w
+ * 0 <= a1 < w
+ * 0 <= a2 < w^N
+ * w/2 <= b0 < w
+ * 0 <= b2 < w^N
+ * a < w*b
+ * I.e. the two top words of a are a0:a1, the top word of b is
+ * b0, we ensured that b0 is "full" (high bit set), and a is
+ * such that the quotient q = a/b fits on one word (0 <= q < w).
+ *
+ * If a = b*q + r (with 0 <= r < q), we can estimate q by
+ * doing an Euclidean division on the top words:
+ * a0*w+a1 = b0*u + v (with 0 <= v < w)
+ * Then the following holds:
+ * 0 <= u <= w
+ * u-2 <= q <= u
+ */
+ a0 = br_i32_word(x, m_bitlen - 32);
+ hi = x[mlen];
+ memmove(x + 2, x + 1, (mlen - 1) * sizeof *x);
+ x[1] = z;
+ a1 = br_i32_word(x, m_bitlen - 32);
+ b0 = br_i32_word(m, m_bitlen - 32);
+
+ /*
+ * We estimate a divisor q. If the quotient returned by br_div()
+ * is g:
+ * -- If a0 == b0 then g == 0; we want q = 0xFFFFFFFF.
+ * -- Otherwise:
+ * -- if g == 0 then we set q = 0;
+ * -- otherwise, we set q = g - 1.
+ * The properties described above then ensure that the true
+ * quotient is q-1, q or q+1.
+ */
+ g = br_div(a0, a1, b0);
+ q = MUX(EQ(a0, b0), 0xFFFFFFFF, MUX(EQ(g, 0), 0, g - 1));
+
+ /*
+ * We subtract q*m from x (with the extra high word of value 'hi').
+ * Since q may be off by 1 (in either direction), we may have to
+ * add or subtract m afterwards.
+ *
+ * The 'tb' flag will be true (1) at the end of the loop if the
+ * result is greater than or equal to the modulus (not counting
+ * 'hi' or the carry).
+ */
+ cc = 0;
+ tb = 1;
+ for (u = 1; u <= mlen; u ++) {
+ uint32_t mw, zw, xw, nxw;
+ uint64_t zl;
+
+ mw = m[u];
+ zl = MUL(mw, q) + cc;
+ cc = (uint32_t)(zl >> 32);
+ zw = (uint32_t)zl;
+ xw = x[u];
+ nxw = xw - zw;
+ cc += (uint64_t)GT(nxw, xw);
+ x[u] = nxw;
+ tb = MUX(EQ(nxw, mw), tb, GT(nxw, mw));
+ }
+
+ /*
+ * If we underestimated q, then either cc < hi (one extra bit
+ * beyond the top array word), or cc == hi and tb is true (no
+ * extra bit, but the result is not lower than the modulus). In
+ * these cases we must subtract m once.
+ *
+ * Otherwise, we may have overestimated, which will show as
+ * cc > hi (thus a negative result). Correction is adding m once.
+ */
+ chf = (uint32_t)(cc >> 32);
+ clow = (uint32_t)cc;
+ over = chf | GT(clow, hi);
+ under = ~over & (tb | (~chf & LT(clow, hi)));
+ br_i32_add(x, m, over);
+ br_i32_sub(x, m, under);
+}
--- /dev/null
+/*
+ * 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 inner.h */
+uint32_t
+br_i32_ninv32(uint32_t x)
+{
+ uint32_t y;
+
+ y = 2 - x;
+ y *= 2 - y * x;
+ y *= 2 - y * x;
+ y *= 2 - y * x;
+ y *= 2 - y * x;
+ return MUX(x & 1, -y, 0);
+}
--- /dev/null
+/*
+ * 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 inner.h */
+void
+br_i32_reduce(uint32_t *x, const uint32_t *a, const uint32_t *m)
+{
+ uint32_t m_bitlen, a_bitlen;
+ size_t mlen, alen, u;
+
+ m_bitlen = m[0];
+ mlen = (m_bitlen + 31) >> 5;
+
+ x[0] = m_bitlen;
+ if (m_bitlen == 0) {
+ return;
+ }
+
+ /*
+ * If the source is shorter, then simply copy all words from a[]
+ * and zero out the upper words.
+ */
+ a_bitlen = a[0];
+ alen = (a_bitlen + 31) >> 5;
+ if (a_bitlen < m_bitlen) {
+ memcpy(x + 1, a + 1, alen * sizeof *a);
+ for (u = alen; u < mlen; u ++) {
+ x[u + 1] = 0;
+ }
+ return;
+ }
+
+ /*
+ * The source length is at least equal to that of the modulus.
+ * We must thus copy N-1 words, and input the remaining words
+ * one by one.
+ */
+ memcpy(x + 1, a + 2 + (alen - mlen), (mlen - 1) * sizeof *a);
+ x[mlen] = 0;
+ for (u = 1 + alen - mlen; u > 0; u --) {
+ br_i32_muladd_small(x, a[u], m);
+ }
+}
--- /dev/null
+/*
+ * 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 inner.h */
+uint32_t
+br_i32_sub(uint32_t *a, const uint32_t *b, uint32_t ctl)
+{
+ uint32_t cc;
+ size_t u, m;
+
+ cc = 0;
+ m = (a[0] + 63) >> 5;
+ for (u = 1; u < m; u ++) {
+ uint32_t aw, bw, naw;
+
+ aw = a[u];
+ bw = b[u];
+ naw = aw - bw - cc;
+
+ /*
+ * Carry is 1 if naw > aw. Carry is 1 also if naw == aw
+ * AND the carry was already 1.
+ */
+ cc = (cc & EQ(naw, aw)) | GT(naw, aw);
+ a[u] = MUX(ctl, naw, aw);
+ }
+ return cc;
+}
--- /dev/null
+/*
+ * 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 inner.h */
+void
+br_i32_to_monty(uint32_t *x, const uint32_t *m)
+{
+ uint32_t k;
+
+ for (k = (m[0] + 31) >> 5; k > 0; k --) {
+ br_i32_muladd_small(x, 0, m);
+ }
+}
--- /dev/null
+/*
+ * 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"
+
+static inline size_t
+block_size(const br_hash_class *dig)
+{
+ unsigned ls;
+
+ ls = (unsigned)(dig->desc >> BR_HASHDESC_LBLEN_OFF)
+ & BR_HASHDESC_LBLEN_MASK;
+ return (size_t)1 << ls;
+}
+
+static void
+process_key(const br_hash_class **hc, void *ks,
+ const void *key, size_t key_len, unsigned bb)
+{
+ unsigned char tmp[256];
+ size_t blen, u;
+
+ blen = block_size(*hc);
+ memcpy(tmp, key, key_len);
+ for (u = 0; u < key_len; u ++) {
+ tmp[u] ^= (unsigned char)bb;
+ }
+ memset(tmp + key_len, bb, blen - key_len);
+ (*hc)->init(hc);
+ (*hc)->update(hc, tmp, blen);
+ (*hc)->state(hc, ks);
+}
+
+/* see bearssl.h */
+void
+br_hmac_key_init(br_hmac_key_context *kc,
+ const br_hash_class *dig, const void *key, size_t key_len)
+{
+ br_hmac_allhash_context hc;
+ unsigned char kbuf[64];
+
+ kc->dig_vtable = dig;
+ hc.vtable = dig;
+ if (key_len > block_size(dig)) {
+ dig->init(&hc.vtable);
+ dig->update(&hc.vtable, key, key_len);
+ dig->out(&hc.vtable, kbuf);
+ key = kbuf;
+ key_len = br_digest_size(dig);
+ }
+ process_key(&hc.vtable, kc->ksi, key, key_len, 0x36);
+ process_key(&hc.vtable, kc->kso, key, key_len, 0x5C);
+}
+
+/* see bearssl.h */
+void
+br_hmac_init(br_hmac_context *ctx,
+ const br_hmac_key_context *kc, size_t out_len)
+{
+ const br_hash_class *dig;
+ size_t blen, hlen;
+
+ dig = kc->dig_vtable;
+ blen = block_size(dig);
+ dig->init(&ctx->dig.vtable);
+ dig->set_state(&ctx->dig.vtable, kc->ksi, (uint64_t)blen);
+ memcpy(ctx->kso, kc->kso, sizeof kc->kso);
+ hlen = br_digest_size(dig);
+ if (out_len > 0 && out_len < hlen) {
+ hlen = out_len;
+ }
+ ctx->out_len = hlen;
+}
+
+/* see bearssl.h */
+void
+br_hmac_update(br_hmac_context *ctx, const void *data, size_t len)
+{
+ ctx->dig.vtable->update(&ctx->dig.vtable, data, len);
+}
+
+/* see bearssl.h */
+size_t
+br_hmac_out(const br_hmac_context *ctx, void *out)
+{
+ const br_hash_class *dig;
+ br_hmac_allhash_context hc;
+ unsigned char tmp[64];
+ size_t blen, hlen;
+
+ dig = ctx->dig.vtable;
+ dig->out(&ctx->dig.vtable, tmp);
+ blen = block_size(dig);
+ dig->init(&hc.vtable);
+ dig->set_state(&hc.vtable, ctx->kso, (uint64_t)blen);
+ hlen = br_digest_size(dig);
+ dig->update(&hc.vtable, tmp, hlen);
+ dig->out(&hc.vtable, tmp);
+ memcpy(out, tmp, ctx->out_len);
+ return ctx->out_len;
+}
--- /dev/null
+/*
+ * 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"
+
+static inline size_t
+hash_size(const br_hash_class *dig)
+{
+ return (unsigned)(dig->desc >> BR_HASHDESC_OUT_OFF)
+ & BR_HASHDESC_OUT_MASK;
+}
+
+static inline size_t
+block_size(const br_hash_class *dig)
+{
+ unsigned ls;
+
+ ls = (unsigned)(dig->desc >> BR_HASHDESC_LBLEN_OFF)
+ & BR_HASHDESC_LBLEN_MASK;
+ return (size_t)1 << ls;
+}
+
+/* see bearssl.h */
+size_t
+br_hmac_outCT(const br_hmac_context *ctx,
+ const void *data, size_t len, size_t min_len, size_t max_len,
+ void *out)
+{
+ /*
+ * Method implemented here is inspired from the descriptions on:
+ * https://www.imperialviolet.org/2013/02/04/luckythirteen.html
+ *
+ * Principle: we input bytes one by one. We use a MUX to push
+ * padding bytes instead of data bytes when appropriate. At each
+ * block limit, we get the current hash function state: this is
+ * a potential output, since we handle MD padding ourselves.
+ *
+ * be 1 for big-endian, 0 for little-endian
+ * po minimal MD padding length
+ * bs block size (always a power of 2)
+ * hlen hash output size
+ */
+
+ const br_hash_class *dig;
+ br_hmac_allhash_context hc;
+ int be;
+ uint32_t po, bs;
+ uint32_t kr, km, kl, kz, u;
+ uint64_t count, ncount, bit_len;
+ unsigned char tmp1[64], tmp2[64];
+ size_t hlen;
+
+ /*
+ * Copy the current hash context.
+ */
+ hc = ctx->dig;
+
+ /*
+ * Get function-specific information.
+ */
+ dig = hc.vtable;
+ be = (dig->desc & BR_HASHDESC_MD_PADDING_BE) != 0;
+ po = 9;
+ if (dig->desc & BR_HASHDESC_MD_PADDING_128) {
+ po += 8;
+ }
+ bs = block_size(dig);
+ hlen = hash_size(dig);
+
+ /*
+ * Get current input length and compute total bit length.
+ */
+ count = dig->state(&hc.vtable, tmp1);
+ bit_len = (count + (uint64_t)len) << 3;
+
+ /*
+ * We can input the blocks that we are sure we will use.
+ * This offers better performance (no MUX for these blocks)
+ * and also ensures that the remaining lengths fit on 32 bits.
+ */
+ ncount = (count + (uint64_t)min_len) & ~(uint64_t)(bs - 1);
+ if (ncount > count) {
+ size_t zlen;
+
+ zlen = (size_t)(ncount - count);
+ dig->update(&hc.vtable, data, zlen);
+ data = (const unsigned char *)data + zlen;
+ len -= zlen;
+ max_len -= zlen;
+ count = ncount;
+ }
+
+ /*
+ * At that point:
+ * -- 'count' contains the number of bytes already processed
+ * (in total).
+ * -- We must input 'len' bytes. 'min_len' is unimportant: we
+ * used it to know how many full blocks we could process
+ * directly. Now only len and max_len matter.
+ *
+ * We compute kr, kl, kz and km.
+ * kr number of input bytes already in the current block
+ * km index of the first byte after the end of the last padding
+ * block, if length is max_len
+ * kz index of the last byte of the actual last padding block
+ * kl index of the start of the encoded length
+ *
+ * km, kz and kl are counted from the current offset in the
+ * input data.
+ */
+ kr = (uint32_t)count & (bs - 1);
+ kz = ((kr + (uint32_t)len + po + bs - 1) & ~(bs - 1)) - 1 - kr;
+ kl = kz - 7;
+ km = ((kr + (uint32_t)max_len + po + bs - 1) & ~(bs - 1)) - kr;
+
+ /*
+ * We must now process km bytes. For index u from 0 to km-1:
+ * d is from data[] if u < max_len, 0x00 otherwise
+ * e is an encoded length byte or 0x00, depending on u
+ * The tests for d and e need not be constant-time, since
+ * they relate only to u and max_len, not to the actual length.
+ *
+ * Actual input length is then:
+ * d if u < len
+ * 0x80 if u == len
+ * 0x00 if u > len and u < kl
+ * e if u >= kl
+ *
+ * Hash state is obtained whenever we reach a full block. This
+ * is the result we want if and only if u == kz.
+ */
+ for (u = 0; u < km; u ++) {
+ uint32_t v;
+ uint32_t d, e, x0, x1;
+ unsigned char x[1];
+
+ d = (u < max_len) ? ((const unsigned char *)data)[u] : 0x00;
+ v = (kr + u) & (bs - 1);
+ if (v >= (bs - 8)) {
+ unsigned j;
+
+ j = (v - (bs - 8)) << 3;
+ if (be) {
+ e = (uint32_t)(bit_len >> (56 - j));
+ } else {
+ e = (uint32_t)(bit_len >> j);
+ }
+ e &= 0xFF;
+ } else {
+ e = 0x00;
+ }
+ x0 = MUX(EQ(u, (uint32_t)len), 0x80, d);
+ x1 = MUX(LT(u, kl), 0x00, e);
+ x[0] = MUX(LE(u, (uint32_t)len), x0, x1);
+ dig->update(&hc.vtable, x, 1);
+ if (v == (bs - 1)) {
+ dig->state(&hc.vtable, tmp1);
+ CCOPY(EQ(u, kz), tmp2, tmp1, hlen);
+ }
+ }
+
+ /*
+ * Inner hash output is in tmp2[]; we finish processing.
+ */
+ dig->init(&hc.vtable);
+ dig->set_state(&hc.vtable, ctx->kso, (uint64_t)bs);
+ dig->update(&hc.vtable, tmp2, hlen);
+ dig->out(&hc.vtable, tmp2);
+ memcpy(out, tmp2, ctx->out_len);
+ return ctx->out_len;
+}
--- /dev/null
+/*
+ * 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.h */
+void
+br_hmac_drbg_init(br_hmac_drbg_context *ctx,
+ const br_hash_class *digest_class, const void *seed, size_t len)
+{
+ size_t hlen;
+
+ ctx->vtable = &br_hmac_drbg_vtable;
+ hlen = br_digest_size(digest_class);
+ memset(ctx->K, 0x00, hlen);
+ memset(ctx->V, 0x01, hlen);
+ ctx->digest_class = digest_class;
+ br_hmac_drbg_update(ctx, seed, len);
+}
+
+/* see bearssl.h */
+void
+br_hmac_drbg_generate(br_hmac_drbg_context *ctx, void *out, size_t len)
+{
+ const br_hash_class *dig;
+ br_hmac_key_context kc;
+ br_hmac_context hc;
+ size_t hlen;
+ unsigned char *buf;
+ unsigned char x;
+
+ dig = ctx->digest_class;
+ hlen = br_digest_size(dig);
+ br_hmac_key_init(&kc, dig, ctx->K, hlen);
+ buf = out;
+ while (len > 0) {
+ size_t clen;
+
+ br_hmac_init(&hc, &kc, 0);
+ br_hmac_update(&hc, ctx->V, hlen);
+ br_hmac_out(&hc, ctx->V);
+ clen = hlen;
+ if (clen > len) {
+ clen = len;
+ }
+ memcpy(buf, ctx->V, clen);
+ buf += clen;
+ len -= clen;
+ }
+
+ /*
+ * To prepare the state for the next request, we should call
+ * br_hmac_drbg_update() with an empty additional seed. However,
+ * we already have an initialized HMAC context with the right
+ * initial key, and we don't want to push another one on the
+ * stack, so we inline that update() call here.
+ */
+ br_hmac_init(&hc, &kc, 0);
+ br_hmac_update(&hc, ctx->V, hlen);
+ x = 0x00;
+ br_hmac_update(&hc, &x, 1);
+ br_hmac_out(&hc, ctx->K);
+ br_hmac_key_init(&kc, dig, ctx->K, hlen);
+ br_hmac_init(&hc, &kc, 0);
+ br_hmac_update(&hc, ctx->V, hlen);
+ br_hmac_out(&hc, ctx->V);
+}
+
+/* see bearssl.h */
+void
+br_hmac_drbg_update(br_hmac_drbg_context *ctx, const void *seed, size_t len)
+{
+ const br_hash_class *dig;
+ br_hmac_key_context kc;
+ br_hmac_context hc;
+ size_t hlen;
+ unsigned char x;
+
+ dig = ctx->digest_class;
+ hlen = br_digest_size(dig);
+
+ /*
+ * 1. K = HMAC(K, V || 0x00 || seed)
+ */
+ br_hmac_key_init(&kc, dig, ctx->K, hlen);
+ br_hmac_init(&hc, &kc, 0);
+ br_hmac_update(&hc, ctx->V, hlen);
+ x = 0x00;
+ br_hmac_update(&hc, &x, 1);
+ br_hmac_update(&hc, seed, len);
+ br_hmac_out(&hc, ctx->K);
+ br_hmac_key_init(&kc, dig, ctx->K, hlen);
+
+ /*
+ * 2. V = HMAC(K, V)
+ */
+ br_hmac_init(&hc, &kc, 0);
+ br_hmac_update(&hc, ctx->V, hlen);
+ br_hmac_out(&hc, ctx->V);
+
+ /*
+ * 3. If the additional seed is empty, then stop here.
+ */
+ if (len == 0) {
+ return;
+ }
+
+ /*
+ * 4. K = HMAC(K, V || 0x01 || seed)
+ */
+ br_hmac_init(&hc, &kc, 0);
+ br_hmac_update(&hc, ctx->V, hlen);
+ x = 0x01;
+ br_hmac_update(&hc, &x, 1);
+ br_hmac_update(&hc, seed, len);
+ br_hmac_out(&hc, ctx->K);
+ br_hmac_key_init(&kc, dig, ctx->K, hlen);
+
+ /*
+ * 5. V = HMAC(K, V)
+ */
+ br_hmac_init(&hc, &kc, 0);
+ br_hmac_update(&hc, ctx->V, hlen);
+ br_hmac_out(&hc, ctx->V);
+}
+
+/* see bearssl.h */
+const br_prng_class br_hmac_drbg_vtable = {
+ sizeof(br_hmac_drbg_context),
+ (void (*)(const br_prng_class **, const void *, const void *, size_t))
+ &br_hmac_drbg_init,
+ (void (*)(const br_prng_class **, void *, size_t))
+ &br_hmac_drbg_generate,
+ (void (*)(const br_prng_class **, const void *, size_t))
+ &br_hmac_drbg_update
+};
--- /dev/null
+/*
+ * 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_rsa.h */
+uint32_t
+br_rsa_i31_pkcs1_sign(const unsigned char *hash_oid,
+ const unsigned char *hash, size_t hash_len,
+ const br_rsa_private_key *sk, unsigned char *x)
+{
+ size_t u, x3, xlen;
+
+ /*
+ * Padded hash value has format:
+ * 00 01 FF .. FF 00 30 x1 30 x2 06 x3 OID 05 00 04 x4 HASH
+ *
+ * with the following rules:
+ *
+ * -- Total length is equal to the modulus length (unsigned
+ * encoding).
+ *
+ * -- There must be at least eight bytes of value 0xFF.
+ *
+ * -- x4 is equal to the hash length (hash_len).
+ *
+ * -- x3 is equal to the encoded OID value length (hash_oid[0]).
+ *
+ * -- x2 = x3 + 4.
+ *
+ * -- x1 = x2 + x4 + 4 = x3 + x4 + 8.
+ *
+ * Note: the "05 00" is optional (signatures with and without
+ * that sequence exist in practice), but notes in PKCS#1 seem to
+ * indicate that the presence of that sequence (specifically,
+ * an ASN.1 NULL value for the hash parameters) may be slightly
+ * more "standard" than the opposite.
+ */
+ xlen = (sk->n_bitlen + 7) >> 3;
+
+ if (hash_oid == NULL) {
+ if (xlen < hash_len + 11) {
+ return 0;
+ }
+ x[0] = 0x00;
+ x[1] = 0x01;
+ u = xlen - hash_len;
+ memset(x + 2, 0xFF, u - 3);
+ x[u - 1] = 0x00;
+ } else {
+ x3 = hash_oid[0];
+
+ /*
+ * Check that there is enough room for all the elements,
+ * including at least eight bytes of value 0xFF.
+ */
+ if (xlen < (x3 + hash_len + 21)) {
+ return 0;
+ }
+ x[0] = 0x00;
+ x[1] = 0x01;
+ u = xlen - x3 - hash_len - 11;
+ memset(x + 2, 0xFF, u - 2);
+ x[u] = 0x00;
+ x[u + 1] = 0x30;
+ x[u + 2] = x3 + hash_len + 8;
+ x[u + 3] = 0x30;
+ x[u + 4] = x3 + 4;
+ x[u + 5] = 0x06;
+ memcpy(x + u + 6, hash_oid, x3 + 1);
+ u += x3 + 7;
+ x[u ++] = 0x05;
+ x[u ++] = 0x00;
+ x[u ++] = 0x04;
+ x[u ++] = hash_len;
+ }
+ memcpy(x + u, hash, hash_len);
+
+ /*
+ * Do the actual computation.
+ */
+ return br_rsa_i31_private(x, sk);
+}
--- /dev/null
+/*
+ * 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_rsa.h */
+uint32_t
+br_rsa_i31_pkcs1_vrfy(const unsigned char *x, size_t xlen,
+ const unsigned char *hash_oid, size_t hash_len,
+ const br_rsa_public_key *pk, unsigned char *hash_out)
+{
+ static const unsigned char pad1[] = {
+ 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+ };
+
+ unsigned char sig[BR_MAX_RSA_SIZE >> 3];
+ unsigned char pad2[43];
+ size_t u, x2, x3, pad_len, zlen;
+
+ if (xlen > (sizeof sig) || xlen < 11) {
+ return 0;
+ }
+ memcpy(sig, x, xlen);
+ if (!br_rsa_i31_public(sig, xlen, pk)) {
+ return 0;
+ }
+
+ /*
+ * Expected format:
+ * 00 01 FF ... FF 00 30 x1 30 x2 06 x3 OID [ 05 00 ] 04 x4 HASH
+ *
+ * with the following rules:
+ *
+ * -- Total length is that of the modulus and the signature
+ * (this was already verified by br_rsa_i31_public()).
+ *
+ * -- There are at least eight bytes of value 0xFF.
+ *
+ * -- x4 is equal to the hash length (hash_len).
+ *
+ * -- x3 is equal to the encoded OID value length (so x3 is the
+ * first byte of hash_oid[]).
+ *
+ * -- If the "05 00" is present, then x2 == x3 + 4; otherwise,
+ * x2 == x3 + 2.
+ *
+ * -- x1 == x2 + x4 + 4.
+ *
+ * So the total length after the last "FF" is either x3 + x4 + 11
+ * (with the "05 00") or x3 + x4 + 9 (without the "05 00").
+ */
+
+ /*
+ * Check the "00 01 FF .. FF 00" with at least eight 0xFF bytes.
+ * The comparaison is valid because we made sure that the signature
+ * is at least 11 bytes long.
+ */
+ if (memcmp(sig, pad1, sizeof pad1) != 0) {
+ return 0;
+ }
+ for (u = sizeof pad1; u < xlen; u ++) {
+ if (sig[u] != 0xFF) {
+ break;
+ }
+ }
+
+ /*
+ * Remaining length is xlen - u bytes (including the 00 just
+ * after the last FF). This must be equal to one of the two
+ * possible values (depending on whether the "05 00" sequence is
+ * present or not).
+ */
+ if (hash_oid == NULL) {
+ if (xlen - u != hash_len + 1 || sig[u] != 0x00) {
+ return 0;
+ }
+ } else {
+ x3 = hash_oid[0];
+ pad_len = x3 + 9;
+ memset(pad2, 0, pad_len);
+ zlen = xlen - u - hash_len;
+ if (zlen == pad_len) {
+ x2 = x3 + 2;
+ } else if (zlen == pad_len + 2) {
+ x2 = x3 + 4;
+ pad_len = zlen;
+ pad2[pad_len - 4] = 0x05;
+ } else {
+ return 0;
+ }
+ pad2[1] = 0x30;
+ pad2[2] = x2 + hash_len + 4;
+ pad2[3] = 0x30;
+ pad2[4] = x2;
+ pad2[5] = 0x06;
+ memcpy(pad2 + 6, hash_oid, x3 + 1);
+ pad2[pad_len - 2] = 0x04;
+ pad2[pad_len - 1] = hash_len;
+ if (memcmp(pad2, sig + u, pad_len) != 0) {
+ return 0;
+ }
+ }
+ memcpy(hash_out, sig + xlen - hash_len, hash_len);
+ return 1;
+}
--- /dev/null
+/*
+ * 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"
+
+#define U (1 + ((BR_MAX_RSA_FACTOR + 30) / 31))
+
+/* see bearssl_rsa.h */
+uint32_t
+br_rsa_i31_private(unsigned char *x, const br_rsa_private_key *sk)
+{
+ const unsigned char *p, *q;
+ size_t plen, qlen;
+ uint32_t tmp[6 * U];
+ uint32_t *mp, *mq, *s1, *s2, *t1, *t2, *t3;
+ uint32_t p0i, q0i;
+ size_t xlen;
+
+ /*
+ * All our temporary buffers are from the tmp[] array.
+ *
+ * The mp, mq, s1, s2, t1 and t2 buffers are large enough to
+ * contain a RSA factor. The t3 buffer can contain a complete
+ * RSA modulus. t3 shares its storage space with s2, s1 and t1,
+ * in that order (this is important, see below).
+ */
+ mq = tmp;
+ mp = tmp + U;
+ t2 = tmp + 2 * U;
+ s2 = tmp + 3 * U;
+ s1 = tmp + 4 * U;
+ t1 = tmp + 5 * U;
+ t3 = s2;
+
+ /*
+ * Compute the actual lengths (in bytes) of p and q, and check
+ * that they fit within our stack buffers.
+ */
+ p = sk->p;
+ plen = sk->plen;
+ while (plen > 0 && *p == 0) {
+ p ++;
+ plen --;
+ }
+ q = sk->q;
+ qlen = sk->qlen;
+ while (qlen > 0 && *q == 0) {
+ q ++;
+ qlen --;
+ }
+ if (plen > (BR_MAX_RSA_FACTOR >> 3)
+ || qlen > (BR_MAX_RSA_FACTOR >> 3))
+ {
+ return 0;
+ }
+
+ /*
+ * Decode p and q.
+ */
+ br_i31_decode(mp, p, plen);
+ br_i31_decode(mq, q, qlen);
+
+ /*
+ * Compute signature length (in bytes).
+ */
+ xlen = (sk->n_bitlen + 7) >> 3;
+
+ /*
+ * Compute s1 = x^dp mod p.
+ */
+ p0i = br_i31_ninv31(mp[1]);
+ br_i31_decode_reduce(s1, x, xlen, mp);
+ br_i31_modpow(s1, sk->dp, sk->dplen, mp, p0i, t1, t2);
+
+ /*
+ * Compute s2 = x^dq mod q.
+ */
+ q0i = br_i31_ninv31(mq[1]);
+ br_i31_decode_reduce(s2, x, xlen, mq);
+ br_i31_modpow(s2, sk->dq, sk->dqlen, mq, q0i, t1, t2);
+
+ /*
+ * Compute:
+ * h = (s1 - s2)*(1/q) mod p
+ * s1 is an integer modulo p, but s2 is modulo q. PKCS#1 is
+ * unclear about whether p may be lower than q (some existing,
+ * widely deployed implementations of RSA don't tolerate p < q),
+ * but we want to support that occurrence, so we need to use the
+ * reduction function.
+ *
+ * Since we use br_i31_decode_reduce() for iq (purportedly, the
+ * inverse of q modulo p), we also tolerate improperly large
+ * values for this parameter.
+ */
+ br_i31_reduce(t2, s2, mp);
+ br_i31_add(s1, mp, br_i31_sub(s1, t2, 1));
+ br_i31_to_monty(s1, mp);
+ br_i31_decode_reduce(t1, sk->iq, sk->iqlen, mp);
+ br_i31_montymul(t2, s1, t1, mp, p0i);
+
+ /*
+ * h is now in t2. We compute the final result:
+ * s = s2 + q*h
+ * All these operations are non-modular.
+ *
+ * We need mq, s2 and t2. We use the t3 buffer as destination.
+ * The buffers mp, s1 and t1 are no longer needed. Moreover,
+ * the first step is to copy s2 into the destination buffer t3.
+ * We thus arranged for t3 to actually share space with s2, and
+ * to be followed by the space formerly used by s1 and t1.
+ */
+ br_i31_mulacc(t3, mq, t2);
+
+ /*
+ * Encode the result. Since we already checked the value of xlen,
+ * we can just use it right away.
+ */
+ br_i31_encode(x, xlen, t3);
+
+ /*
+ * The only error conditions remaining at that point are invalid
+ * values for p and q (even integers).
+ */
+ return p0i & q0i & 1;
+}
--- /dev/null
+/*
+ * 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_rsa.h */
+uint32_t
+br_rsa_i31_public(unsigned char *x, size_t xlen,
+ const br_rsa_public_key *pk)
+{
+ const unsigned char *n;
+ size_t nlen;
+ uint32_t m[1 + ((BR_MAX_RSA_SIZE + 30) / 31)];
+ uint32_t a[1 + ((BR_MAX_RSA_SIZE + 30) / 31)];
+ uint32_t t1[1 + ((BR_MAX_RSA_SIZE + 30) / 31)];
+ uint32_t t2[1 + ((BR_MAX_RSA_SIZE + 30) / 31)];
+ uint32_t m0i, r;
+
+ /*
+ * Get the actual length of the modulus, and see if it fits within
+ * our stack buffer. We also check that the length of x[] is valid.
+ */
+ n = pk->n;
+ nlen = pk->nlen;
+ while (nlen > 0 && *n == 0) {
+ n ++;
+ nlen --;
+ }
+ if (nlen == 0 || nlen > (BR_MAX_RSA_SIZE >> 3) || xlen != nlen) {
+ return 0;
+ }
+ br_i31_decode(m, n, nlen);
+ m0i = br_i31_ninv31(m[1]);
+
+ /*
+ * Note: if m[] is even, then m0i == 0. Otherwise, m0i must be
+ * an odd integer.
+ */
+ r = m0i & 1;
+
+ /*
+ * Decode x[] into a[]; we also check that its value is proper.
+ */
+ r &= br_i31_decode_mod(a, x, xlen, m);
+
+ /*
+ * Compute the modular exponentiation.
+ */
+ br_i31_modpow(a, pk->e, pk->elen, m, m0i, t1, t2);
+
+ /*
+ * Encode the result.
+ */
+ br_i31_encode(x, xlen, a);
+ return r;
+}
--- /dev/null
+/*
+ * 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_rsa.h */
+uint32_t
+br_rsa_i32_pkcs1_sign(const unsigned char *hash_oid,
+ const unsigned char *hash, size_t hash_len,
+ const br_rsa_private_key *sk, unsigned char *x)
+{
+ size_t u, x3, xlen;
+
+ /*
+ * Padded hash value has format:
+ * 00 01 FF .. FF 00 30 x1 30 x2 06 x3 OID 05 00 04 x4 HASH
+ *
+ * with the following rules:
+ *
+ * -- Total length is equal to the modulus length (unsigned
+ * encoding).
+ *
+ * -- There must be at least eight bytes of value 0xFF.
+ *
+ * -- x4 is equal to the hash length (hash_len).
+ *
+ * -- x3 is equal to the encoded OID value length (hash_oid[0]).
+ *
+ * -- x2 = x3 + 4.
+ *
+ * -- x1 = x2 + x4 + 4 = x3 + x4 + 8.
+ *
+ * Note: the "05 00" is optional (signatures with and without
+ * that sequence exist in practice), but notes in PKCS#1 seem to
+ * indicate that the presence of that sequence (specifically,
+ * an ASN.1 NULL value for the hash parameters) may be slightly
+ * more "standard" than the opposite.
+ */
+ xlen = (sk->n_bitlen + 7) >> 3;
+
+ if (hash_oid == NULL) {
+ if (xlen < hash_len + 11) {
+ return 0;
+ }
+ u = xlen - hash_len;
+ memset(x + 2, 0xFF, u - 3);
+ x[u - 1] = 0x00;
+ } else {
+ x3 = hash_oid[0];
+
+ /*
+ * Check that there is enough room for all the elements,
+ * including at least eight bytes of value 0xFF.
+ */
+ if (xlen < (x3 + hash_len + 21)) {
+ return 0;
+ }
+ x[0] = 0x00;
+ x[1] = 0x01;
+ u = xlen - x3 - hash_len - 11;
+ memset(x + 2, 0xFF, u - 2);
+ x[u] = 0x00;
+ x[u + 1] = 0x30;
+ x[u + 2] = x3 + hash_len + 8;
+ x[u + 3] = 0x30;
+ x[u + 4] = x3 + 4;
+ x[u + 5] = 0x06;
+ memcpy(x + u + 6, hash_oid, x3 + 1);
+ u += x3 + 7;
+ x[u ++] = 0x05;
+ x[u ++] = 0x00;
+ x[u ++] = 0x04;
+ x[u ++] = hash_len;
+ }
+ memcpy(x + u + 4, hash, hash_len);
+
+ /*
+ * Do the actual computation.
+ */
+ return br_rsa_i32_private(x, sk);
+}
--- /dev/null
+/*
+ * 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_rsa.h */
+uint32_t
+br_rsa_i32_pkcs1_vrfy(const unsigned char *x, size_t xlen,
+ const unsigned char *hash_oid, size_t hash_len,
+ const br_rsa_public_key *pk, unsigned char *hash_out)
+{
+ static const unsigned char pad1[] = {
+ 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+ };
+
+ unsigned char sig[BR_MAX_RSA_SIZE >> 3];
+ unsigned char pad2[43];
+ size_t u, x2, x3, pad_len, zlen;
+
+ if (xlen > (sizeof sig) || xlen < 11) {
+ return 0;
+ }
+ memcpy(sig, x, xlen);
+ if (!br_rsa_i32_public(sig, xlen, pk)) {
+ return 0;
+ }
+
+ /*
+ * Expected format:
+ * 00 01 FF ... FF 00 30 x1 30 x2 06 x3 OID [ 05 00 ] 04 x4 HASH
+ *
+ * with the following rules:
+ *
+ * -- Total length is that of the modulus and the signature
+ * (this was already verified by br_rsa_i32_public()).
+ *
+ * -- There are at least eight bytes of value 0xFF.
+ *
+ * -- x4 is equal to the hash length (hash_len).
+ *
+ * -- x3 is equal to the encoded OID value length (so x3 is the
+ * first byte of hash_oid[]).
+ *
+ * -- If the "05 00" is present, then x2 == x3 + 4; otherwise,
+ * x2 == x3 + 2.
+ *
+ * -- x1 == x2 + x4 + 4.
+ *
+ * So the total length after the last "FF" is either x3 + x4 + 11
+ * (with the "05 00") or x3 + x4 + 9 (without the "05 00").
+ */
+
+ /*
+ * Check the "00 01 FF .. FF 00" with at least eight 0xFF bytes.
+ * The comparaison is valid because we made sure that the signature
+ * is at least 11 bytes long.
+ */
+ if (memcmp(sig, pad1, sizeof pad1) != 0) {
+ return 0;
+ }
+ for (u = sizeof pad1; u < xlen; u ++) {
+ if (sig[u] != 0xFF) {
+ break;
+ }
+ }
+
+ /*
+ * Remaining length is xlen - u bytes (including the 00 just
+ * after the last FF). This must be equal to one of the two
+ * possible values (depending on whether the "05 00" sequence is
+ * present or not).
+ */
+ if (hash_oid == NULL) {
+ if (xlen - u != hash_len + 1 || sig[u] != 0x00) {
+ return 0;
+ }
+ } else {
+ x3 = hash_oid[0];
+ pad_len = x3 + 9;
+ memset(pad2, 0, pad_len);
+ zlen = xlen - u - hash_len;
+ if (zlen == pad_len) {
+ x2 = x3 + 2;
+ } else if (zlen == pad_len + 2) {
+ x2 = x3 + 4;
+ pad_len = zlen;
+ pad2[pad_len - 4] = 0x05;
+ } else {
+ return 0;
+ }
+ pad2[1] = 0x30;
+ pad2[2] = x2 + hash_len + 4;
+ pad2[3] = 0x30;
+ pad2[4] = x2;
+ pad2[5] = 0x06;
+ memcpy(pad2 + 6, hash_oid, x3 + 1);
+ pad2[pad_len - 2] = 0x04;
+ pad2[pad_len - 1] = hash_len;
+ if (memcmp(pad2, sig + u, pad_len) != 0) {
+ return 0;
+ }
+ }
+ memcpy(hash_out, sig + xlen - hash_len, hash_len);
+ return 1;
+}
--- /dev/null
+/*
+ * 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"
+
+#define U (1 + (BR_MAX_RSA_FACTOR >> 5))
+
+/* see bearssl_rsa.h */
+uint32_t
+br_rsa_i32_private(unsigned char *x, const br_rsa_private_key *sk)
+{
+ const unsigned char *p, *q;
+ size_t plen, qlen;
+ uint32_t tmp[6 * U];
+ uint32_t *mp, *mq, *s1, *s2, *t1, *t2, *t3;
+ uint32_t p0i, q0i;
+ size_t xlen;
+
+ /*
+ * All our temporary buffers are from the tmp[] array.
+ *
+ * The mp, mq, s1, s2, t1 and t2 buffers are large enough to
+ * contain a RSA factor. The t3 buffer can contain a complete
+ * RSA modulus. t3 shares its storage space with s2, s1 and t1,
+ * in that order (this is important, see below).
+ */
+ mq = tmp;
+ mp = tmp + U;
+ t2 = tmp + 2 * U;
+ s2 = tmp + 3 * U;
+ s1 = tmp + 4 * U;
+ t1 = tmp + 5 * U;
+ t3 = s2;
+
+ /*
+ * Compute the actual lengths (in bytes) of p and q, and check
+ * that they fit within our stack buffers.
+ */
+ p = sk->p;
+ plen = sk->plen;
+ while (plen > 0 && *p == 0) {
+ p ++;
+ plen --;
+ }
+ q = sk->q;
+ qlen = sk->qlen;
+ while (qlen > 0 && *q == 0) {
+ q ++;
+ qlen --;
+ }
+ if (plen > (BR_MAX_RSA_FACTOR >> 3)
+ || qlen > (BR_MAX_RSA_FACTOR >> 3))
+ {
+ return 0;
+ }
+
+ /*
+ * Decode p and q.
+ */
+ br_i32_decode(mp, p, plen);
+ br_i32_decode(mq, q, qlen);
+
+ /*
+ * obsolete -- we do not compute the length of n, it is now
+ * an input parameter.
+ br_i32_zero(t3, mp[0]);
+ br_i32_mulacc(t3, mp, mq);
+ n_bitlen = br_i32_bit_length(t3 + 1, (t3[0] + 31) >> 5);
+ if (xlen != ((n_bitlen + 7) >> 3)) {
+ return 0;
+ }
+ */
+ xlen = (sk->n_bitlen + 7) >> 3;
+
+ /*
+ * Compute s1 = x^dp mod p.
+ */
+ p0i = br_i32_ninv32(mp[1]);
+ br_i32_decode_reduce(s1, x, xlen, mp);
+ br_i32_modpow(s1, sk->dp, sk->dplen, mp, p0i, t1, t2);
+
+ /*
+ * Compute s2 = x^dq mod q.
+ */
+ q0i = br_i32_ninv32(mq[1]);
+ br_i32_decode_reduce(s2, x, xlen, mq);
+ br_i32_modpow(s2, sk->dq, sk->dqlen, mq, q0i, t1, t2);
+
+ /*
+ * Compute:
+ * h = (s1 - s2)*(1/q) mod p
+ * s1 is an integer modulo p, but s2 is modulo q. PKCS#1 is
+ * unclear about whether p may be lower than q (some existing,
+ * widely deployed implementations of RSA don't tolerate p < q),
+ * but we want to support that occurrence, so we need to use the
+ * reduction function.
+ *
+ * Since we use br_i32_decode_reduce() for iq (purportedly, the
+ * inverse of q modulo p), we also tolerate improperly large
+ * values for this parameter.
+ */
+ br_i32_reduce(t2, s2, mp);
+ br_i32_add(s1, mp, br_i32_sub(s1, t2, 1));
+ br_i32_to_monty(s1, mp);
+ br_i32_decode_reduce(t1, sk->iq, sk->iqlen, mp);
+ br_i32_montymul(t2, s1, t1, mp, p0i);
+
+ /*
+ * h is now in t2. We compute the final result:
+ * s = s2 + q*h
+ * All these operations are non-modular.
+ *
+ * We need mq, s2 and t2. We use the t3 buffer as destination.
+ * The buffers mp, s1 and t1 are no longer needed. Moreover,
+ * the first step is to copy s2 into the destination buffer t3.
+ * We thus arranged for t3 to actually share space with s2, and
+ * to be followed by the space formerly used by s1 and t1.
+ */
+ br_i32_mulacc(t3, mq, t2);
+
+ /*
+ * Encode the result. Since we already checked the value of xlen,
+ * we can just use it right away.
+ */
+ br_i32_encode(x, xlen, t3);
+
+ /*
+ * The only error conditions remaining at that point are invalid
+ * values for p and q (even integers).
+ */
+ return p0i & q0i & 1;
+}
--- /dev/null
+/*
+ * 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_rsa.h */
+uint32_t
+br_rsa_i32_public(unsigned char *x, size_t xlen,
+ const br_rsa_public_key *pk)
+{
+ const unsigned char *n;
+ size_t nlen;
+ uint32_t m[1 + (BR_MAX_RSA_SIZE >> 5)];
+ uint32_t a[1 + (BR_MAX_RSA_SIZE >> 5)];
+ uint32_t t1[1 + (BR_MAX_RSA_SIZE >> 5)];
+ uint32_t t2[1 + (BR_MAX_RSA_SIZE >> 5)];
+ uint32_t m0i, r;
+
+ /*
+ * Get the actual length of the modulus, and see if it fits within
+ * our stack buffer. We also check that the length of x[] is valid.
+ */
+ n = pk->n;
+ nlen = pk->nlen;
+ while (nlen > 0 && *n == 0) {
+ n ++;
+ nlen --;
+ }
+ if (nlen == 0 || nlen > (BR_MAX_RSA_SIZE >> 3) || xlen != nlen) {
+ return 0;
+ }
+ br_i32_decode(m, n, nlen);
+ m0i = br_i32_ninv32(m[1]);
+
+ /*
+ * Note: if m[] is even, then m0i == 0. Otherwise, m0i must be
+ * an odd integer.
+ */
+ r = m0i & 1;
+
+ /*
+ * Decode x[] into a[]; we also check that its value is proper.
+ */
+ r &= br_i32_decode_mod(a, x, xlen, m);
+
+ /*
+ * Compute the modular exponentiation.
+ */
+ br_i32_modpow(a, pk->e, pk->elen, m, m0i, t1, t2);
+
+ /*
+ * Encode the result.
+ */
+ br_i32_encode(x, xlen, a);
+ return r;
+}
--- /dev/null
+/*
+ * 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_rsa.h */
+uint32_t
+br_rsa_ssl_decrypt(br_rsa_private core, const br_rsa_private_key *sk,
+ unsigned char *data, size_t len)
+{
+ uint32_t x;
+ size_t u;
+
+ /*
+ * A first check on length. Since this test works only on the
+ * buffer length, it needs not (and cannot) be constant-time.
+ */
+ if (len < 59 || len != (sk->n_bitlen + 7) >> 3) {
+ return 0;
+ }
+ x = core(data, sk);
+
+ x &= EQ(data[0], 0x00);
+ x &= EQ(data[1], 0x02);
+ for (u = 2; u < (len - 49); u ++) {
+ x &= NEQ(data[u], 0);
+ }
+ x &= EQ(data[len - 49], 0x00);
+ memmove(data, data + len - 48, 48);
+ return x;
+}
--- /dev/null
+/*
+ * 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 inner.h */
+void
+br_tls_phash(void *dst, size_t len,
+ const br_hash_class *dig,
+ const void *secret, size_t secret_len,
+ const char *label, const void *seed, size_t seed_len)
+{
+ unsigned char *buf;
+ unsigned char tmp[64], a[64];
+ br_hmac_key_context kc;
+ br_hmac_context hc;
+ size_t label_len, hlen;
+
+ if (len == 0) {
+ return;
+ }
+ buf = dst;
+ for (label_len = 0; label[label_len]; label_len ++);
+ hlen = br_digest_size(dig);
+ br_hmac_key_init(&kc, dig, secret, secret_len);
+ br_hmac_init(&hc, &kc, 0);
+ br_hmac_update(&hc, label, label_len);
+ br_hmac_update(&hc, seed, seed_len);
+ br_hmac_out(&hc, a);
+ for (;;) {
+ size_t u;
+
+ br_hmac_init(&hc, &kc, 0);
+ br_hmac_update(&hc, a, hlen);
+ br_hmac_update(&hc, label, label_len);
+ br_hmac_update(&hc, seed, seed_len);
+ br_hmac_out(&hc, tmp);
+ for (u = 0; u < hlen && u < len; u ++) {
+ buf[u] ^= tmp[u];
+ }
+ buf += u;
+ len -= u;
+ if (len == 0) {
+ return;
+ }
+ br_hmac_init(&hc, &kc, 0);
+ br_hmac_update(&hc, a, hlen);
+ br_hmac_out(&hc, a);
+ }
+}
--- /dev/null
+/*
+ * 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.h */
+void
+br_tls10_prf(void *dst, size_t len,
+ const void *secret, size_t secret_len,
+ const char *label, const void *seed, size_t seed_len)
+{
+ const unsigned char *s1;
+ size_t slen;
+
+ s1 = secret;
+ slen = (secret_len + 1) >> 1;
+ memset(dst, 0, len);
+ br_tls_phash(dst, len, &br_md5_vtable,
+ s1, slen, label, seed, seed_len);
+ br_tls_phash(dst, len, &br_sha1_vtable,
+ s1 + secret_len - slen, slen, label, seed, seed_len);
+}
--- /dev/null
+/*
+ * 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.h */
+void
+br_tls12_sha256_prf(void *dst, size_t len,
+ const void *secret, size_t secret_len,
+ const char *label, const void *seed, size_t seed_len)
+{
+ memset(dst, 0, len);
+ br_tls_phash(dst, len, &br_sha256_vtable,
+ secret, secret_len, label, seed, seed_len);
+}
--- /dev/null
+/*
+ * 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.h */
+void
+br_tls12_sha384_prf(void *dst, size_t len,
+ const void *secret, size_t secret_len,
+ const char *label, const void *seed, size_t seed_len)
+{
+ memset(dst, 0, len);
+ br_tls_phash(dst, len, &br_sha384_vtable,
+ secret, secret_len, label, seed, seed_len);
+}
--- /dev/null
+/*
+ * 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_ssl.h */
+void
+br_ssl_client_zero(br_ssl_client_context *cc)
+{
+ /*
+ * For really standard C, we should explicitly set to NULL all
+ * pointers, and 0 all other fields. However, on all our target
+ * architectures, a direct memset() will work, be faster, and
+ * use a lot less code.
+ */
+ memset(cc, 0, sizeof *cc);
+}
+
+/* see bearssl_ssl.h */
+int
+br_ssl_client_reset(br_ssl_client_context *cc,
+ const char *server_name, int resume_session)
+{
+ size_t n;
+
+ br_ssl_engine_set_buffer(&cc->eng, NULL, 0, 0);
+ cc->eng.version_out = cc->eng.version_min;
+ if (!resume_session) {
+ br_ssl_client_forget_session(cc);
+ }
+ if (!br_ssl_engine_init_rand(&cc->eng)) {
+ return 0;
+ }
+
+ /*
+ * We always set back the "reneg" flag to 0 because we use it
+ * to distinguish between first handshake and renegotiation.
+ * Note that "renegotiation" and "session resumption" are two
+ * different things.
+ */
+ cc->eng.reneg = 0;
+
+ if (server_name == NULL) {
+ cc->eng.server_name[0] = 0;
+ } else {
+ n = strlen(server_name) + 1;
+ if (n > sizeof cc->eng.server_name) {
+ br_ssl_engine_fail(&cc->eng, BR_ERR_BAD_PARAM);
+ return 0;
+ }
+ memcpy(cc->eng.server_name, server_name, n);
+ }
+
+ br_ssl_engine_hs_reset(&cc->eng,
+ br_ssl_hs_client_init_main, br_ssl_hs_client_run);
+ return br_ssl_engine_last_error(&cc->eng) == BR_ERR_OK;
+}
--- /dev/null
+/*
+ * 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_ssl.h */
+void
+br_ssl_client_init_full(br_ssl_client_context *cc,
+ br_x509_minimal_context *xc,
+ const br_x509_trust_anchor *trust_anchors, size_t trust_anchors_num)
+{
+ /*
+ * The "full" profile supports all implemented cipher suites.
+ *
+ * Rationale for suite order, from most important to least
+ * important rule:
+ *
+ * -- Don't use 3DES if AES is available.
+ * -- Try to have Forward Secrecy (ECDHE suite) if possible.
+ * -- When not using Forward Secrecy, ECDH key exchange is
+ * better than RSA key exchange (slightly more expensive on the
+ * client, but much cheaper on the server, and it implies smaller
+ * messages).
+ * -- GCM is better than CBC.
+ * -- AES-128 is preferred over AES-256 (AES-128 is already
+ * strong enough, and AES-256 is 40% more expensive).
+ */
+ static const uint16_t suites[] = {
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ BR_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+ BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
+ BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ BR_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,
+ BR_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,
+ BR_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384,
+ BR_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384,
+ BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
+ BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
+ BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,
+ BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,
+ BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
+ BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
+ BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
+ BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
+ BR_TLS_RSA_WITH_AES_128_GCM_SHA256,
+ BR_TLS_RSA_WITH_AES_256_GCM_SHA384,
+ BR_TLS_RSA_WITH_AES_128_CBC_SHA256,
+ BR_TLS_RSA_WITH_AES_256_CBC_SHA256,
+ BR_TLS_RSA_WITH_AES_128_CBC_SHA,
+ BR_TLS_RSA_WITH_AES_256_CBC_SHA,
+ BR_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ BR_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ BR_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ BR_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
+ BR_TLS_RSA_WITH_3DES_EDE_CBC_SHA
+ };
+
+ /*
+ * 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;
+
+ /*
+ * Reset client context and set supported versions from TLS-1.0
+ * to TLS-1.2 (inclusive).
+ */
+ br_ssl_client_zero(cc);
+ br_ssl_engine_set_versions(&cc->eng, BR_TLS10, BR_TLS12);
+
+ /*
+ * X.509 engine uses SHA-256 to hash certificate DN (for
+ * comparisons).
+ */
+ br_x509_minimal_init(xc, &br_sha256_vtable,
+ trust_anchors, trust_anchors_num);
+
+ /*
+ * Set suites and asymmetric crypto implementations. We use the
+ * "i31" code for RSA (it is somewhat faster than the "i32"
+ * implementation).
+ * TODO: change that when better implementations are made available.
+ */
+ br_ssl_engine_set_suites(&cc->eng, suites,
+ (sizeof suites) / (sizeof suites[0]));
+ br_ssl_client_set_rsapub(cc, &br_rsa_i31_public);
+ br_ssl_client_set_rsavrfy(cc, &br_rsa_i31_pkcs1_vrfy);
+ br_ssl_engine_set_ec(&cc->eng, &br_ec_prime_i31);
+ br_ssl_client_set_ecdsa(cc, &br_ecdsa_i31_vrfy_asn1);
+ 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);
+
+ /*
+ * Set supported hash functions, for the SSL engine and for the
+ * X.509 engine.
+ */
+ for (id = br_md5_ID; id <= br_sha512_ID; id ++) {
+ const br_hash_class *hc;
+
+ hc = hashes[id - 1];
+ br_ssl_engine_set_hash(&cc->eng, id, hc);
+ br_x509_minimal_set_hash(xc, id, hc);
+ }
+
+ /*
+ * Link the X.509 engine in the SSL engine.
+ */
+ br_ssl_engine_set_x509(&cc->eng, &xc->vtable);
+
+ /*
+ * Set the PRF implementations.
+ */
+ br_ssl_engine_set_prf10(&cc->eng, &br_tls10_prf);
+ br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf);
+ br_ssl_engine_set_prf_sha384(&cc->eng, &br_tls12_sha384_prf);
+
+ /*
+ * Symmetric encryption. We use the "constant-time"
+ * implementations, which are the safest.
+ *
+ * On architectures detected as "64-bit", use the 64-bit
+ * versions (aes_ct64, ghash_ctmul64).
+ */
+#if BR_64
+ br_ssl_engine_set_aes_cbc(&cc->eng,
+ &br_aes_ct64_cbcenc_vtable,
+ &br_aes_ct64_cbcdec_vtable);
+ br_ssl_engine_set_aes_ctr(&cc->eng,
+ &br_aes_ct64_ctr_vtable);
+ br_ssl_engine_set_ghash(&cc->eng,
+ &br_ghash_ctmul64);
+#else
+ br_ssl_engine_set_aes_cbc(&cc->eng,
+ &br_aes_ct_cbcenc_vtable,
+ &br_aes_ct_cbcdec_vtable);
+ br_ssl_engine_set_aes_ctr(&cc->eng,
+ &br_aes_ct_ctr_vtable);
+ br_ssl_engine_set_ghash(&cc->eng,
+ &br_ghash_ctmul);
+#endif
+ br_ssl_engine_set_des_cbc(&cc->eng,
+ &br_des_ct_cbcenc_vtable,
+ &br_des_ct_cbcdec_vtable);
+
+ /*
+ * Set the SSL record engines (CBC, GCM).
+ */
+ br_ssl_engine_set_cbc(&cc->eng,
+ &br_sslrec_in_cbc_vtable,
+ &br_sslrec_out_cbc_vtable);
+ br_ssl_engine_set_gcm(&cc->eng,
+ &br_sslrec_in_gcm_vtable,
+ &br_sslrec_out_gcm_vtable);
+}
--- /dev/null
+/*
+ * 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"
+
+/*
+ * If BR_USE_URANDOM is not defined, then try to autodetect its presence
+ * through compiler macros.
+ */
+#ifndef BR_USE_URANDOM
+
+/*
+ * Macro values documented on:
+ * https://sourceforge.net/p/predef/wiki/OperatingSystems/
+ *
+ * Only the most common systems have been included here for now. This
+ * should be enriched later on.
+ */
+#if defined _AIX \
+ || defined __ANDROID__ \
+ || defined __FreeBSD__ \
+ || defined __NetBSD__ \
+ || defined __OpenBSD__ \
+ || defined __DragonFly__ \
+ || defined __linux__ \
+ || (defined __sun && (defined __SVR4 || defined __svr4__)) \
+ || (defined __APPLE__ && defined __MACH__)
+#define BR_USE_URANDOM 1
+#endif
+
+#endif
+
+/*
+ * If BR_USE_WIN32_RAND is not defined, perform autodetection here.
+ */
+#ifndef BR_USE_WIN32_RAND
+
+#if defined _WIN32 || defined _WIN64
+#define BR_USE_WIN32_RAND 1
+#endif
+
+#endif
+
+#if BR_USE_URANDOM
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#endif
+
+#if BR_USE_WIN32_RAND
+#include <windows.h>
+#include <wincrypt.h>
+#pragma comment(lib, "advapi32")
+#endif
+
+/* ==================================================================== */
+/*
+ * This part of the file does the low-level record management.
+ */
+
+/*
+ * IMPLEMENTATION NOTES
+ * ====================
+ *
+ * In this file, we designate by "input" (and the "i" letter) the "recv"
+ * operations: incoming records from the peer, from which payload data
+ * is obtained, and must be extracted by the application (or the SSL
+ * handshake engine). Similarly, "output" (and the "o" letter) is for
+ * "send": payload data injected by the application (and SSL handshake
+ * engine), to be wrapped into records, that are then conveyed to the
+ * peer over the transport medium.
+ *
+ * The input and output buffers may be distinct or shared. When
+ * shared, input and output cannot occur concurrently; the caller
+ * must make sure that it never needs to output data while input
+ * data has been received. In practice, a shared buffer prevents
+ * pipelining of HTTP requests, or similar protocols; however, a
+ * shared buffer saves RAM.
+ *
+ * The input buffer is pointed to by 'ibuf' and has size 'ibuf_len';
+ * the output buffer is pointed to by 'obuf' and has size 'obuf_len'.
+ * From the size of these buffers is derived the maximum fragment
+ * length, which will be honoured upon sending records; regardless of
+ * that length, incoming records will be processed as long as they
+ * fit in the input buffer, and their length still complies with the
+ * protocol specification (maximum plaintext payload length is 16384
+ * bytes).
+ *
+ * Three registers are used to manage buffering in ibuf, called ixa,
+ * ixb and ixc. Similarly, three registers are used to manage buffering
+ * in obuf, called oxa, oxb and oxc.
+ *
+ *
+ * At any time, the engine is in one of the following modes:
+ * -- Failed mode: an error occurs, no I/O can happen.
+ * -- Input mode: the engine can either receive record bytes from the
+ * transport layer, or it has some buffered payload bytes to yield.
+ * -- Output mode: the engine can either receive payload bytes, or it
+ * has some record bytes to send to the transport layer.
+ * -- Input/Output mode: both input and output modes are active. When
+ * the buffer is shared, this can happen only when the buffer is empty
+ * (no buffered payload bytes or record bytes in either direction).
+ *
+ *
+ * Failed mode:
+ * ------------
+ *
+ * I/O failed for some reason (invalid received data, not enough room
+ * for the next record...). No I/O may ever occur again for this context,
+ * until an explicit reset is performed. This mode, and the error code,
+ * are also used for protocol errors, especially handshake errors.
+ *
+ *
+ * Input mode:
+ * -----------
+ *
+ * ixa index within ibuf[] for the currently read data
+ * ixb maximum index within ibuf[] for the currently read data
+ * ixc number of bytes not yet received for the current record
+ *
+ * -- When ixa == ixb, there is no available data for readers. When
+ * ixa != ixb, there is available data and it starts at offset ixa.
+ *
+ * -- When waiting for the next record header, ixa and ixb are equal
+ * and contain a value ranging from 0 to 4; ixc is equal to 5-ixa.
+ *
+ * -- When the header has been received, record data is obtained. The
+ * ixc field records how many bytes are still needed to reach the
+ * end of the current record.
+ *
+ * ** If encryption is active, then ixa and ixb are kept equal, and
+ * point to the end of the currently received record bytes. When
+ * ixc reaches 0, decryption/MAC is applied, and ixa and ixb are
+ * adjusted.
+ *
+ * ** If encryption is not active, then ixa and ixb are distinct
+ * and data can be read right away. Additional record data is
+ * obtained only when ixa == ixb.
+ *
+ * Note: in input mode and no encryption, records larger than the buffer
+ * size are allowed. When encryption is active, the complete record must
+ * fit within the buffer, since it cannot be decrypted/MACed until it
+ * has been completely received.
+ *
+ * -- When receiving the next record header, 'version_in' contains the
+ * expected input version (0 if not expecting a specific version); on
+ * mismatch, the mode switches to 'failed'.
+ *
+ * -- When the header has been received, 'version_in' contains the received
+ * version. It is up to the caller to check and adjust the 'version_in' field
+ * to implement the required semantics.
+ *
+ * -- The 'record_type_in' field is updated with the incoming record type
+ * when the next record header has been received.
+ *
+ *
+ * Output mode:
+ * ------------
+ *
+ * oxa index within obuf[] for the currently accumulated data
+ * oxb maximum index within obuf[] for record data
+ * oxc pointer for start of record data, and for record sending
+ *
+ * -- When oxa != oxb, more data can be accumulated into the current
+ * record; when oxa == oxb, a closed record is being sent.
+ *
+ * -- When accumulating data, oxc points to the start of the data.
+ *
+ * -- During record sending, oxa (and oxb) point to the next record byte
+ * to send, and oxc indicates the end of the current record.
+ *
+ * Note: sent records must fit within the buffer, since the header is
+ * adjusted only when the complete record has been assembled.
+ *
+ * -- The 'version_out' and 'record_type_out' fields are used to build the
+ * record header when the mode is switched to 'sending'.
+ *
+ *
+ * Modes:
+ * ------
+ *
+ * The state register iomode contains one of the following values:
+ *
+ * BR_IO_FAILED I/O failed
+ * BR_IO_IN input mode
+ * BR_IO_OUT output mode
+ * BR_IO_INOUT input/output mode
+ *
+ * Whether encryption is active on incoming records is indicated by the
+ * incrypt flag. For outgoing records, there is no such flag; "encryption"
+ * is always considered active, but initially uses functions that do not
+ * encrypt anything. The 'incrypt' flag is needed because when there is
+ * no active encryption, records larger than the I/O buffer are accepted.
+ *
+ * Note: we do not support no-encryption modes (MAC only).
+ *
+ * TODO: implement GCM support
+ *
+ *
+ * Misc:
+ * -----
+ *
+ * 'max_frag_len' is the maximum plaintext size for an outgoing record.
+ * By default, it is set to the maximum value that fits in the provided
+ * buffers, in the following list: 512, 1024, 2048, 4096, 16384. The
+ * caller may change it if needed, but the new value MUST still fit in
+ * the buffers, and it MUST be one of the list above for compatibility
+ * with the Maximum Fragment Length extension.
+ *
+ * For incoming records, only the total buffer length and current
+ * encryption mode impact the maximum length for incoming records. The
+ * 'max_frag_len' value is still adjusted so that records up to that
+ * length can be both received and sent.
+ *
+ *
+ * Offsets and lengths:
+ * --------------------
+ *
+ * When sending fragments with TLS-1.1+, the maximum overhead is:
+ * 5 bytes for the record header
+ * 16 bytes for the explicit IV
+ * 48 bytes for the MAC (HMAC/SHA-384)
+ * 16 bytes for the padding (AES)
+ * so a total of 85 extra bytes. Note that we support block cipher sizes
+ * up to 16 bytes (AES) and HMAC output sizes up to 48 bytes (SHA-384).
+ *
+ * With TLS-1.0 and CBC mode, we apply a 1/n-1 split, for a maximum
+ * overhead of:
+ * 5 bytes for the first record header
+ * 32 bytes for the first record payload (AES-CBC + HMAC/SHA-1)
+ * 5 bytes for the second record header
+ * 20 bytes for the MAC (HMAC/SHA-1)
+ * 16 bytes for the padding (AES)
+ * -1 byte to account for the payload byte in the first record
+ * so a total of 77 extra bytes at most, less than the 85 bytes above.
+ * Note that with TLS-1.0, the MAC is HMAC with either MD5 or SHA-1, but
+ * no other hash function.
+ *
+ * The implementation does not try to send larger records when the current
+ * encryption mode has less overhead.
+ *
+ * Maximum input record overhead is:
+ * 5 bytes for the record header
+ * 16 bytes for the explicit IV (TLS-1.1+)
+ * 48 bytes for the MAC (HMAC/SHA-384)
+ * 256 bytes for the padding
+ * so a total of 325 extra bytes.
+ *
+ * When receiving the next record header, it is written into the buffer
+ * bytes 0 to 4 (inclusive). Record data is always written into buf[]
+ * starting at offset 5. When encryption is active, the plaintext data
+ * may start at a larger offset (e.g. because of an explicit IV).
+ */
+
+#define MAX_OUT_OVERHEAD 85
+#define MAX_IN_OVERHEAD 325
+
+/* see inner.h */
+void
+br_ssl_engine_fail(br_ssl_engine_context *rc, int err)
+{
+ if (rc->iomode != BR_IO_FAILED) {
+ rc->iomode = BR_IO_FAILED;
+ rc->err = err;
+ }
+}
+
+/*
+ * Adjust registers for a new incoming record.
+ */
+static void
+make_ready_in(br_ssl_engine_context *rc)
+{
+ rc->ixa = rc->ixb = 0;
+ rc->ixc = 5;
+ if (rc->iomode == BR_IO_IN) {
+ rc->iomode = BR_IO_INOUT;
+ }
+}
+
+/*
+ * Adjust registers for a new outgoing record.
+ */
+static void
+make_ready_out(br_ssl_engine_context *rc)
+{
+ size_t a, b;
+
+ a = 5;
+ b = rc->obuf_len - a;
+ rc->out.vtable->max_plaintext(&rc->out.vtable, &a, &b);
+ if ((b - a) > rc->max_frag_len) {
+ b = a + rc->max_frag_len;
+ }
+ rc->oxa = a;
+ rc->oxb = b;
+ rc->oxc = a;
+ if (rc->iomode == BR_IO_OUT) {
+ rc->iomode = BR_IO_INOUT;
+ }
+}
+
+/* see inner.h */
+void
+br_ssl_engine_new_max_frag_len(br_ssl_engine_context *rc, unsigned max_frag_len)
+{
+ size_t nxb;
+
+ rc->max_frag_len = max_frag_len;
+ nxb = rc->oxc + max_frag_len;
+ if (rc->oxa < rc->oxb && rc->oxb > nxb && rc->oxa < nxb) {
+ rc->oxb = nxb;
+ }
+}
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_set_buffer(br_ssl_engine_context *rc,
+ void *buf, size_t buf_len, int bidi)
+{
+ if (buf == NULL) {
+ br_ssl_engine_set_buffers_bidi(rc, NULL, 0, NULL, 0);
+ } else {
+ /*
+ * In bidirectional mode, we want to maximise input
+ * buffer size, since we support arbitrary fragmentation
+ * when sending, but the peer will not necessarily
+ * comply to any low fragment length (in particular if
+ * we are the server, because the maximum fragment
+ * length extension is under client control).
+ *
+ * We keep a minimum size of 512 bytes for the plaintext
+ * of our outgoing records.
+ *
+ * br_ssl_engine_set_buffers_bidi() will compute the maximum
+ * fragment length for outgoing records by using the minimum
+ * of allocated spaces for both input and output records,
+ * rounded down to a standard length.
+ */
+ if (bidi) {
+ size_t w;
+
+ if (buf_len < (512 + MAX_IN_OVERHEAD
+ + 512 + MAX_OUT_OVERHEAD))
+ {
+ rc->iomode = BR_IO_FAILED;
+ rc->err = BR_ERR_BAD_PARAM;
+ return;
+ } else if (buf_len < (16384 + MAX_IN_OVERHEAD
+ + 512 + MAX_OUT_OVERHEAD))
+ {
+ w = 512 + MAX_OUT_OVERHEAD;
+ } else {
+ w = buf_len - (16384 + MAX_IN_OVERHEAD);
+ }
+ br_ssl_engine_set_buffers_bidi(rc,
+ buf, buf_len - w,
+ (unsigned char *)buf + w, w);
+ } else {
+ br_ssl_engine_set_buffers_bidi(rc,
+ buf, buf_len, NULL, 0);
+ }
+ }
+}
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_set_buffers_bidi(br_ssl_engine_context *rc,
+ void *ibuf, size_t ibuf_len, void *obuf, size_t obuf_len)
+{
+ rc->iomode = BR_IO_INOUT;
+ rc->incrypt = 0;
+ rc->err = BR_ERR_OK;
+ rc->version_in = 0;
+ rc->record_type_in = 0;
+ rc->version_out = 0;
+ rc->record_type_out = 0;
+ if (ibuf == NULL) {
+ if (rc->ibuf == NULL) {
+ br_ssl_engine_fail(rc, BR_ERR_BAD_PARAM);
+ }
+ } else {
+ unsigned u;
+
+ rc->ibuf = ibuf;
+ rc->ibuf_len = ibuf_len;
+ if (obuf == NULL) {
+ obuf = ibuf;
+ obuf_len = ibuf_len;
+ }
+ rc->obuf = obuf;
+ rc->obuf_len = obuf_len;
+
+ /*
+ * Compute the maximum fragment length, that fits for
+ * both incoming and outgoing records. This length will
+ * be used in fragment length negotiation, so we must
+ * honour it both ways. Regardless, larger incoming
+ * records will be accepted, as long as they fit in the
+ * actual buffer size.
+ */
+ for (u = 14; u >= 9; u --) {
+ size_t flen;
+
+ flen = (size_t)1 << u;
+ if (obuf_len >= flen + MAX_OUT_OVERHEAD
+ && ibuf_len >= flen + MAX_IN_OVERHEAD)
+ {
+ break;
+ }
+ }
+ if (u == 8) {
+ br_ssl_engine_fail(rc, BR_ERR_BAD_PARAM);
+ return;
+ } else if (u == 13) {
+ u = 12;
+ }
+ rc->max_frag_len = (size_t)1 << u;
+ rc->log_max_frag_len = u;
+ rc->peer_log_max_frag_len = 0;
+ }
+ rc->out.vtable = &br_sslrec_out_clear_vtable;
+ make_ready_in(rc);
+ make_ready_out(rc);
+}
+
+/*
+ * Clear buffers in both directions.
+ */
+static void
+engine_clearbuf(br_ssl_engine_context *rc)
+{
+ make_ready_in(rc);
+ make_ready_out(rc);
+}
+
+/* see inner.h */
+int
+br_ssl_engine_init_rand(br_ssl_engine_context *cc)
+{
+ /*
+ * TODO: use getrandom() on Linux systems, with a fallback to
+ * opening /dev/urandom if that system call fails.
+ *
+ * Use similar OS facilities on other OS (getentropy() on OpenBSD,
+ * specialized sysctl on NetBSD and FreeBSD...).
+ */
+#if BR_USE_URANDOM
+ if (!cc->rng_os_rand_done) {
+ int f;
+
+ f = open("/dev/urandom", O_RDONLY);
+ if (f >= 0) {
+ unsigned char tmp[32];
+ size_t u;
+
+ for (u = 0; u < sizeof tmp;) {
+ ssize_t len;
+
+ len = read(f, tmp + u, (sizeof tmp) - u);
+ if (len < 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+ break;
+ }
+ u += (size_t)len;
+ }
+ close(f);
+ if (u == sizeof tmp) {
+ br_ssl_engine_inject_entropy(cc, tmp, u);
+ cc->rng_os_rand_done = 1;
+ }
+ }
+ }
+#elif BR_USE_WIN32_RAND
+ if (!cc->rng_os_rand_done) {
+ HCRYPTPROV hp;
+
+ if (CryptAcquireContextW(&hp, 0, 0, PROV_RSA_FULL,
+ CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
+ {
+ BYTE buf[32];
+
+ if (CryptGenRandom(hp, sizeof buf, buf)) {
+ br_ssl_engine_inject_entropy(cc,
+ buf, sizeof buf);
+ cc->rng_os_rand_done = 1;
+ }
+ CryptReleaseContext(hp, 0);
+ }
+ }
+#endif
+
+ if (!cc->rng_init_done) {
+ br_ssl_engine_fail(cc, BR_ERR_NO_RANDOM);
+ return 0;
+ }
+ return 1;
+}
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_inject_entropy(br_ssl_engine_context *cc,
+ const void *data, size_t len)
+{
+ if (cc->rng_init_done) {
+ br_hmac_drbg_update(&cc->rng, data, len);
+ } else {
+ /*
+ * If using TLS-1.2, then SHA-256 or SHA-384 must be
+ * present (or both); we prefer SHA-256 which is faster
+ * for 32-bit systems.
+ *
+ * If using TLS-1.0 or 1.1 then SHA-1 must be present.
+ *
+ * Though HMAC_DRBG/SHA-1 is, as far as we know, as safe
+ * as these things can be, we still prefer the SHA-2
+ * functions over SHA-1, if only for public relations
+ * (known theoretical weaknesses of SHA-1 with regards to
+ * collisions are mostly irrelevant here, but they still
+ * make people nervous).
+ */
+ const br_hash_class *h;
+
+ h = br_multihash_getimpl(&cc->mhash, br_sha256_ID);
+ if (!h) {
+ h = br_multihash_getimpl(&cc->mhash, br_sha384_ID);
+ if (!h) {
+ h = br_multihash_getimpl(&cc->mhash,
+ br_sha1_ID);
+ if (!h) {
+ br_ssl_engine_fail(cc,
+ BR_ERR_BAD_STATE);
+ return;
+ }
+ }
+ }
+ br_hmac_drbg_init(&cc->rng, h, data, len);
+ cc->rng_init_done = 1;
+ }
+}
+
+/*
+ * We define a few internal functions that implement the low-level engine
+ * API for I/O; the external API (br_ssl_engine_sendapp_buf() and similar
+ * functions) is built upon these function, with special processing for
+ * records which are not of type "application data".
+ *
+ * recvrec_buf, recvrec_ack receives bytes from transport medium
+ * sendrec_buf, sendrec_ack send bytes to transport medium
+ * recvpld_buf, recvpld_ack receives payload data from engine
+ * sendpld_buf, sendpld_ack send payload data to engine
+ */
+
+static unsigned char *
+recvrec_buf(const br_ssl_engine_context *rc, size_t *len)
+{
+ if (rc->shutdown_recv) {
+ *len = 0;
+ return NULL;
+ }
+
+ /*
+ * Bytes from the transport can be injected only if the mode is
+ * compatible (in or in/out), and ixa == ixb; ixc then contains
+ * the number of bytes that are still expected (but it may
+ * exceed our buffer size).
+ *
+ * We cannot get "stuck" here (buffer is full, but still more
+ * data is expected) because oversized records are detected when
+ * their header is processed.
+ */
+ switch (rc->iomode) {
+ case BR_IO_IN:
+ case BR_IO_INOUT:
+ if (rc->ixa == rc->ixb) {
+ size_t z;
+
+ z = rc->ixc;
+ if (z > rc->ibuf_len - rc->ixa) {
+ z = rc->ibuf_len - rc->ixa;
+ }
+ *len = z;
+ return rc->ibuf + rc->ixa;
+ }
+ break;
+ }
+ *len = 0;
+ return NULL;
+}
+
+static void
+recvrec_ack(br_ssl_engine_context *rc, size_t len)
+{
+ unsigned char *pbuf;
+ size_t pbuf_len;
+
+ /*
+ * Adjust state if necessary (for a shared input/output buffer):
+ * we got some incoming bytes, so we cannot (temporarily) handle
+ * outgoing data.
+ */
+ if (rc->iomode == BR_IO_INOUT && rc->ibuf == rc->obuf) {
+ rc->iomode = BR_IO_IN;
+ }
+
+ /*
+ * Adjust data pointers.
+ */
+ rc->ixb = (rc->ixa += len);
+ rc->ixc -= len;
+
+ /*
+ * If we are receiving a header and did not fully obtained it
+ * yet, then just wait for the next bytes.
+ */
+ if (rc->ixa < 5) {
+ return;
+ }
+
+ /*
+ * If we just obtained a full header, process it.
+ */
+ if (rc->ixa == 5) {
+ unsigned version;
+ unsigned rlen;
+
+ /*
+ * Get record type and version. We support only versions
+ * 3.x (if the version major number does not match, then
+ * we suppose that the record format is too alien for us
+ * to process it).
+ *
+ * Note: right now, we reject clients that try to send
+ * a ClientHello in a format compatible with SSL-2.0. It
+ * is unclear whether this will ever be supported; and
+ * if we want to support it, then this might be done in
+ * in the server-specific code, not here.
+ */
+ rc->record_type_in = rc->ibuf[0];
+ version = br_dec16be(rc->ibuf + 1);
+ if ((version >> 8) != 3) {
+ br_ssl_engine_fail(rc, BR_ERR_UNSUPPORTED_VERSION);
+ return;
+ }
+
+ /*
+ * We ensure that successive records have the same
+ * version. The handshake code must check and adjust the
+ * variables when necessary to accommodate the protocol
+ * negotiation details.
+ */
+ if (rc->version_in != 0 && rc->version_in != version) {
+ br_ssl_engine_fail(rc, BR_ERR_BAD_VERSION);
+ return;
+ }
+ rc->version_in = version;
+
+ /*
+ * Decode record length. We must check that the length
+ * is valid (relatively to the current encryption mode)
+ * and also (if encryption is active) that the record
+ * will fit in our buffer.
+ *
+ * When no encryption is active, we can process records
+ * by chunks, and thus accept any record up to the
+ * maximum allowed plaintext length (16384 bytes).
+ */
+ rlen = br_dec16be(rc->ibuf + 3);
+ if (rc->incrypt) {
+ if (!rc->in.vtable->check_length(
+ &rc->in.vtable, rlen))
+ {
+ br_ssl_engine_fail(rc, BR_ERR_BAD_LENGTH);
+ return;
+ }
+ if (rlen > (rc->ibuf_len - 5)) {
+ br_ssl_engine_fail(rc, BR_ERR_TOO_LARGE);
+ return;
+ }
+ } else {
+ if (rlen > 16384) {
+ br_ssl_engine_fail(rc, BR_ERR_BAD_LENGTH);
+ return;
+ }
+ }
+
+ /*
+ * If the record is completely empty then we must switch
+ * to a new record. Note that, in that case, we
+ * completely ignore the record type, which is fitting
+ * since we received no actual data of that type.
+ *
+ * A completely empty record is technically allowed as
+ * long as encryption/MAC is not active, i.e. before
+ * completion of the first handshake. It it still weird;
+ * it might conceptually be useful as a heartbeat or
+ * keep-alive mechanism while some lengthy operation is
+ * going on, e.g. interaction with a human user.
+ */
+ if (rlen == 0) {
+ make_ready_in(rc);
+ } else {
+ rc->ixa = rc->ixb = 5;
+ rc->ixc = rlen;
+ }
+ return;
+ }
+
+ /*
+ * If there is no active encryption, then the data can be read
+ * right away. Note that we do not receive bytes from the
+ * transport medium when we still have payload bytes to be
+ * acknowledged.
+ */
+ if (!rc->incrypt) {
+ rc->ixa = 5;
+ return;
+ }
+
+ /*
+ * Since encryption is active, we must wait for a full record
+ * before processing it.
+ */
+ if (rc->ixc != 0) {
+ return;
+ }
+
+ /*
+ * We got the full record. Decrypt it.
+ */
+ pbuf_len = rc->ixa - 5;
+ pbuf = rc->in.vtable->decrypt(&rc->in.vtable,
+ rc->record_type_in, rc->version_in, rc->ibuf + 5, &pbuf_len);
+ if (pbuf == 0) {
+ br_ssl_engine_fail(rc, BR_ERR_BAD_MAC);
+ return;
+ }
+ rc->ixa = (size_t)(pbuf - rc->ibuf);
+ rc->ixb = rc->ixa + pbuf_len;
+
+ /*
+ * Decryption may have yielded an empty record, in which case
+ * we get back to "ready" state immediately.
+ */
+ if (rc->ixa == rc->ixb) {
+ make_ready_in(rc);
+ }
+}
+
+/* see inner.h */
+int
+br_ssl_engine_recvrec_finished(const br_ssl_engine_context *rc)
+{
+ switch (rc->iomode) {
+ case BR_IO_IN:
+ case BR_IO_INOUT:
+ return rc->ixc == 0 || rc->ixa < 5;
+ default:
+ return 1;
+ }
+}
+
+static unsigned char *
+recvpld_buf(const br_ssl_engine_context *rc, size_t *len)
+{
+ /*
+ * There is payload data to be read only if the mode is
+ * compatible, and ixa != ixb.
+ */
+ switch (rc->iomode) {
+ case BR_IO_IN:
+ case BR_IO_INOUT:
+ *len = rc->ixb - rc->ixa;
+ return (*len == 0) ? NULL : (rc->ibuf + rc->ixa);
+ default:
+ *len = 0;
+ return NULL;
+ }
+}
+
+static void
+recvpld_ack(br_ssl_engine_context *rc, size_t len)
+{
+ rc->ixa += len;
+
+ /*
+ * If we read all the available data, then we either expect
+ * the remainder of the current record (if the current record
+ * was not finished; this may happen when encryption is not
+ * active), or go to "ready" state.
+ */
+ if (rc->ixa == rc->ixb) {
+ if (rc->ixc == 0) {
+ make_ready_in(rc);
+ } else {
+ rc->ixa = rc->ixb = 5;
+ }
+ }
+}
+
+static unsigned char *
+sendpld_buf(const br_ssl_engine_context *rc, size_t *len)
+{
+ /*
+ * Payload data can be injected only if the current mode is
+ * compatible, and oxa != oxb.
+ */
+ switch (rc->iomode) {
+ case BR_IO_OUT:
+ case BR_IO_INOUT:
+ *len = rc->oxb - rc->oxa;
+ return (*len == 0) ? NULL : (rc->obuf + rc->oxa);
+ default:
+ *len = 0;
+ return NULL;
+ }
+}
+
+/*
+ * If some payload bytes have been accumulated, then wrap them into
+ * an outgoing record. Otherwise, this function does nothing, unless
+ * 'force' is non-zero, in which case an empty record is assembled.
+ *
+ * The caller must take care not to invoke this function if the engine
+ * is not currently ready to receive payload bytes to send.
+ */
+static void
+sendpld_flush(br_ssl_engine_context *rc, int force)
+{
+ size_t xlen;
+ unsigned char *buf;
+
+ if (rc->oxa == rc->oxb) {
+ return;
+ }
+ xlen = rc->oxa - rc->oxc;
+ if (xlen == 0 && !force) {
+ return;
+ }
+ buf = rc->out.vtable->encrypt(&rc->out.vtable,
+ rc->record_type_out, rc->version_out,
+ rc->obuf + rc->oxc, &xlen);
+ rc->oxb = rc->oxa = (size_t)(buf - rc->obuf);
+ rc->oxc = rc->oxa + xlen;
+}
+
+static void
+sendpld_ack(br_ssl_engine_context *rc, size_t len)
+{
+ /*
+ * If using a shared buffer, then we may have to modify the
+ * current mode.
+ */
+ if (rc->iomode == BR_IO_INOUT && rc->ibuf == rc->obuf) {
+ rc->iomode = BR_IO_OUT;
+ }
+ rc->oxa += len;
+ if (rc->oxa >= rc->oxb) {
+ sendpld_flush(rc, 0);
+ }
+}
+
+static unsigned char *
+sendrec_buf(const br_ssl_engine_context *rc, size_t *len)
+{
+ /*
+ * When still gathering payload bytes, oxc points to the start
+ * of the record data, so oxc <= oxa. However, when a full
+ * record has been completed, oxc points to the end of the record,
+ * so oxc > oxa.
+ */
+ switch (rc->iomode) {
+ case BR_IO_OUT:
+ case BR_IO_INOUT:
+ if (rc->oxc > rc->oxa) {
+ *len = rc->oxc - rc->oxa;
+ return rc->obuf + rc->oxa;
+ }
+ break;
+ }
+ *len = 0;
+ return NULL;
+}
+
+static void
+sendrec_ack(br_ssl_engine_context *rc, size_t len)
+{
+ rc->oxb = (rc->oxa += len);
+ if (rc->oxa == rc->oxc) {
+ make_ready_out(rc);
+ }
+}
+
+/*
+ * Test whether there is some buffered outgoing record that still must
+ * sent.
+ */
+static inline int
+has_rec_tosend(const br_ssl_engine_context *rc)
+{
+ return rc->oxa == rc->oxb && rc->oxa != rc->oxc;
+}
+
+/*
+ * The "no encryption" mode has no overhead. It limits the payload size
+ * to the maximum size allowed by the standard (16384 bytes); the caller
+ * is responsible for possibly enforcing a smaller fragment length.
+ */
+static void
+clear_max_plaintext(const br_sslrec_out_clear_context *cc,
+ size_t *start, size_t *end)
+{
+ size_t len;
+
+ (void)cc;
+ len = *end - *start;
+ if (len > 16384) {
+ *end = *start + 16384;
+ }
+}
+
+/*
+ * In "no encryption" mode, encryption is trivial (a no-operation) so
+ * we just have to encode the header.
+ */
+static unsigned char *
+clear_encrypt(br_sslrec_out_clear_context *cc,
+ int record_type, unsigned version, void *data, size_t *data_len)
+{
+ unsigned char *buf;
+
+ (void)cc;
+ buf = (unsigned char *)data - 5;
+ buf[0] = record_type;
+ br_enc16be(buf + 1, version);
+ br_enc16be(buf + 3, *data_len);
+ *data_len += 5;
+ return buf;
+}
+
+/* see bearssl_ssl.h */
+const br_sslrec_out_class br_sslrec_out_clear_vtable = {
+ sizeof(br_sslrec_out_clear_context),
+ (void (*)(const br_sslrec_out_class *const *, size_t *, size_t *))
+ &clear_max_plaintext,
+ (unsigned char *(*)(const br_sslrec_out_class **,
+ int, unsigned, void *, size_t *))
+ &clear_encrypt
+};
+
+/* ==================================================================== */
+/*
+ * In this part of the file, we handle the various record types, and
+ * communications with the handshake processor.
+ */
+
+/*
+ * IMPLEMENTATION NOTES
+ * ====================
+ *
+ * The handshake processor is written in T0 and runs as a coroutine.
+ * It receives the contents of all records except application data, and
+ * is responsible for producing the contents of all records except
+ * application data.
+ *
+ * A state flag is maintained, which specifies whether application data
+ * is acceptable or not. When it is set:
+ *
+ * -- Application data can be injected as payload data (provided that
+ * the output buffer is ready for that).
+ *
+ * -- Incoming application data records are accepted, and yield data
+ * that the caller may retrieve.
+ *
+ * When the flag is cleared, application data is not accepted from the
+ * application, and incoming application data records trigger an error.
+ *
+ *
+ * Records of type handshake, alert or change-cipher-spec are handled
+ * by the handshake processor. The handshake processor is written in T0
+ * and runs as a coroutine; it gets invoked whenever one of the following
+ * situations is reached:
+ *
+ * -- An incoming record has type handshake, alert or change-cipher-spec,
+ * and yields data that can be read (zero-length records are thus
+ * ignored).
+ *
+ * -- An outgoing record has just finished being sent, and the "application
+ * data" flag is cleared.
+ *
+ * -- The caller wishes to perform a close (call to br_ssl_engine_close()).
+ *
+ * -- The caller wishes to perform a renegotiation (call to
+ * br_ssl_engine_renegotiate()).
+ *
+ * Whenever the handshake processor is entered, access to the payload
+ * buffers is provided, along with some information about explicit
+ * closures or renegotiations.
+ */
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_set_suites(br_ssl_engine_context *cc,
+ const uint16_t *suites, size_t suites_num)
+{
+ if ((suites_num * sizeof *suites) > sizeof cc->suites_buf) {
+ br_ssl_engine_fail(cc, BR_ERR_BAD_PARAM);
+ return;
+ }
+ memcpy(cc->suites_buf, suites, suites_num * sizeof *suites);
+ cc->suites_num = suites_num;
+}
+
+/*
+ * Give control to handshake processor. 'action' is 1 for a close,
+ * 2 for a renegotiation, or 0 for a jump due to I/O completion.
+ */
+static void
+jump_handshake(br_ssl_engine_context *cc, int action)
+{
+ /*
+ * We use a loop because the handshake processor actions may
+ * allow for more actions; namely, if the processor reads all
+ * input data, then it may allow for output data to be produced,
+ * in case of a shared in/out buffer.
+ */
+ for (;;) {
+ size_t hlen_in, hlen_out;
+
+ /*
+ * Get input buffer. We do not want to provide
+ * application data to the handshake processor (we could
+ * get called with an explicit close or renegotiation
+ * while there is application data ready to be read).
+ */
+ cc->hbuf_in = recvpld_buf(cc, &hlen_in);
+ if (cc->hbuf_in != NULL
+ && cc->record_type_in == BR_SSL_APPLICATION_DATA)
+ {
+ hlen_in = 0;
+ }
+
+ /*
+ * Get output buffer. The handshake processor never
+ * leaves an unfinished outgoing record, so if there is
+ * buffered output, then it MUST be some application
+ * data, so the processor cannot write to it.
+ */
+ cc->saved_hbuf_out = cc->hbuf_out = sendpld_buf(cc, &hlen_out);
+ if (cc->hbuf_out != NULL && br_ssl_engine_has_pld_to_send(cc)) {
+ hlen_out = 0;
+ }
+
+ /*
+ * Note: hlen_in and hlen_out can be both non-zero only if
+ * the input and output buffers are disjoint. Thus, we can
+ * offer both buffers to the handshake code.
+ */
+
+ cc->hlen_in = hlen_in;
+ cc->hlen_out = hlen_out;
+ cc->action = action;
+ cc->hsrun(&cc->cpu);
+ if (cc->hbuf_out != cc->saved_hbuf_out) {
+ sendpld_ack(cc, cc->hbuf_out - cc->saved_hbuf_out);
+ }
+ if (hlen_in != cc->hlen_in) {
+ recvpld_ack(cc, hlen_in - cc->hlen_in);
+ if (cc->hlen_in == 0) {
+ /*
+ * We read all data bytes, which may have
+ * released the output buffer in case it
+ * is shared with the input buffer, and
+ * the handshake code might be waiting for
+ * that.
+ */
+ action = 0;
+ continue;
+ }
+ }
+ break;
+ }
+}
+
+/* see inner.h */
+void
+br_ssl_engine_flush_record(br_ssl_engine_context *cc)
+{
+ if (cc->hbuf_out != cc->saved_hbuf_out) {
+ sendpld_ack(cc, cc->hbuf_out - cc->saved_hbuf_out);
+ }
+ if (br_ssl_engine_has_pld_to_send(cc)) {
+ sendpld_flush(cc, 0);
+ }
+ cc->saved_hbuf_out = cc->hbuf_out = sendpld_buf(cc, &cc->hlen_out);
+}
+
+/* see bearssl_ssl.h */
+unsigned char *
+br_ssl_engine_sendapp_buf(const br_ssl_engine_context *cc, size_t *len)
+{
+ if (!cc->application_data) {
+ *len = 0;
+ return NULL;
+ }
+ return sendpld_buf(cc, len);
+}
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_sendapp_ack(br_ssl_engine_context *cc, size_t len)
+{
+ sendpld_ack(cc, len);
+}
+
+/* see bearssl_ssl.h */
+unsigned char *
+br_ssl_engine_recvapp_buf(const br_ssl_engine_context *cc, size_t *len)
+{
+ if (!cc->application_data
+ || cc->record_type_in != BR_SSL_APPLICATION_DATA)
+ {
+ *len = 0;
+ return NULL;
+ }
+ return recvpld_buf(cc, len);
+}
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_recvapp_ack(br_ssl_engine_context *cc, size_t len)
+{
+ recvpld_ack(cc, len);
+}
+
+/* see bearssl_ssl.h */
+unsigned char *
+br_ssl_engine_sendrec_buf(const br_ssl_engine_context *cc, size_t *len)
+{
+ return sendrec_buf(cc, len);
+}
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_sendrec_ack(br_ssl_engine_context *cc, size_t len)
+{
+ sendrec_ack(cc, len);
+ if (len != 0 && !has_rec_tosend(cc)
+ && (cc->record_type_out != BR_SSL_APPLICATION_DATA
+ || cc->application_data == 0))
+ {
+ jump_handshake(cc, 0);
+ }
+}
+
+/* see bearssl_ssl.h */
+unsigned char *
+br_ssl_engine_recvrec_buf(const br_ssl_engine_context *cc, size_t *len)
+{
+ return recvrec_buf(cc, len);
+}
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_recvrec_ack(br_ssl_engine_context *cc, size_t len)
+{
+ unsigned char *buf;
+
+ recvrec_ack(cc, len);
+ if (br_ssl_engine_closed(cc)) {
+ return;
+ }
+
+ /*
+ * We just received some bytes from the peer. This may have
+ * yielded some payload bytes, in which case we must process
+ * them according to the record type.
+ */
+ buf = recvpld_buf(cc, &len);
+ if (buf != NULL) {
+ switch (cc->record_type_in) {
+ case BR_SSL_CHANGE_CIPHER_SPEC:
+ case BR_SSL_ALERT:
+ case BR_SSL_HANDSHAKE:
+ jump_handshake(cc, 0);
+ break;
+ case BR_SSL_APPLICATION_DATA:
+ if (cc->application_data) {
+ break;
+ }
+ /* Fall through */
+ default:
+ br_ssl_engine_fail(cc, BR_ERR_UNEXPECTED);
+ break;
+ }
+ }
+}
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_close(br_ssl_engine_context *cc)
+{
+ if (!br_ssl_engine_closed(cc)) {
+ jump_handshake(cc, 1);
+ }
+}
+
+/* see bearssl_ssl.h */
+int
+br_ssl_engine_renegotiate(br_ssl_engine_context *cc)
+{
+ if (br_ssl_engine_closed(cc) || cc->reneg == 1) {
+ return 0;
+ }
+ jump_handshake(cc, 2);
+ return 1;
+}
+
+/* see bearssl.h */
+unsigned
+br_ssl_engine_current_state(const br_ssl_engine_context *cc)
+{
+ unsigned s;
+ size_t len;
+
+ if (br_ssl_engine_closed(cc)) {
+ return BR_SSL_CLOSED;
+ }
+
+ s = 0;
+ if (br_ssl_engine_sendrec_buf(cc, &len) != NULL) {
+ s |= BR_SSL_SENDREC;
+ }
+ if (br_ssl_engine_recvrec_buf(cc, &len) != NULL) {
+ s |= BR_SSL_RECVREC;
+ }
+ if (br_ssl_engine_sendapp_buf(cc, &len) != NULL) {
+ s |= BR_SSL_SENDAPP;
+ }
+ if (br_ssl_engine_recvapp_buf(cc, &len) != NULL) {
+ s |= BR_SSL_RECVAPP;
+ }
+ return s;
+}
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_flush(br_ssl_engine_context *cc, int force)
+{
+ if (!br_ssl_engine_closed(cc) && cc->application_data) {
+ sendpld_flush(cc, force);
+ }
+}
+
+/* see inner.h */
+void
+br_ssl_engine_hs_reset(br_ssl_engine_context *cc,
+ void (*hsinit)(void *), void (*hsrun)(void *))
+{
+ engine_clearbuf(cc);
+ cc->cpu.dp = cc->dp_stack;
+ cc->cpu.rp = cc->rp_stack;
+ hsinit(&cc->cpu);
+ cc->hsrun = hsrun;
+ cc->shutdown_recv = 0;
+ cc->application_data = 0;
+ jump_handshake(cc, 0);
+}
+
+/* see inner.h */
+br_tls_prf_impl
+br_ssl_engine_get_PRF(br_ssl_engine_context *cc, int prf_id)
+{
+ if (cc->session.version >= BR_TLS12) {
+ if (prf_id == br_sha384_ID) {
+ return cc->prf_sha384;
+ } else {
+ return cc->prf_sha256;
+ }
+ } else {
+ return cc->prf10;
+ }
+}
+
+/* see inner.h */
+void
+br_ssl_engine_compute_master(br_ssl_engine_context *cc,
+ int prf_id, const void *pms, size_t pms_len)
+{
+ br_tls_prf_impl iprf;
+ unsigned char seed[64];
+
+ iprf = br_ssl_engine_get_PRF(cc, prf_id);
+ memcpy(seed, cc->client_random, 32);
+ memcpy(seed + 32, cc->server_random, 32);
+ iprf(cc->session.master_secret, sizeof cc->session.master_secret,
+ pms, pms_len, "master secret", seed, sizeof seed);
+}
+
+/*
+ * Compute key block.
+ */
+static void
+compute_key_block(br_ssl_engine_context *cc, int prf_id,
+ size_t half_len, unsigned char *kb)
+{
+ br_tls_prf_impl iprf;
+ unsigned char seed[64];
+
+ iprf = br_ssl_engine_get_PRF(cc, prf_id);
+ memcpy(seed, cc->server_random, 32);
+ memcpy(seed + 32, cc->client_random, 32);
+ iprf(kb, half_len << 1,
+ cc->session.master_secret, sizeof cc->session.master_secret,
+ "key expansion", seed, sizeof seed);
+}
+
+/* see inner.h */
+void
+br_ssl_engine_switch_cbc_in(br_ssl_engine_context *cc,
+ int is_client, int prf_id, int mac_id,
+ const br_block_cbcdec_class *bc_impl, size_t cipher_key_len)
+{
+ unsigned char kb[192];
+ unsigned char *cipher_key, *mac_key, *iv;
+ const br_hash_class *imh;
+ size_t mac_key_len, mac_out_len, iv_len;
+
+ imh = br_ssl_engine_get_hash(cc, mac_id);
+ mac_out_len = (imh->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK;
+ mac_key_len = mac_out_len;
+
+ /*
+ * TLS 1.1+ uses per-record explicit IV, so no IV to generate here.
+ */
+ if (cc->session.version >= BR_TLS11) {
+ iv_len = 0;
+ } else {
+ iv_len = bc_impl->block_size;
+ }
+ compute_key_block(cc, prf_id,
+ mac_key_len + cipher_key_len + iv_len, kb);
+ if (is_client) {
+ mac_key = &kb[mac_key_len];
+ cipher_key = &kb[(mac_key_len << 1) + cipher_key_len];
+ iv = &kb[((mac_key_len + cipher_key_len) << 1) + iv_len];
+ } else {
+ mac_key = &kb[0];
+ cipher_key = &kb[mac_key_len << 1];
+ iv = &kb[(mac_key_len + cipher_key_len) << 1];
+ }
+ if (iv_len == 0) {
+ iv = NULL;
+ }
+ cc->icbc_in->init(&cc->in.cbc.vtable,
+ bc_impl, cipher_key, cipher_key_len,
+ imh, mac_key, mac_key_len, mac_out_len, iv);
+ cc->incrypt = 1;
+}
+
+/* see inner.h */
+void
+br_ssl_engine_switch_cbc_out(br_ssl_engine_context *cc,
+ int is_client, int prf_id, int mac_id,
+ const br_block_cbcenc_class *bc_impl, size_t cipher_key_len)
+{
+ unsigned char kb[192];
+ unsigned char *cipher_key, *mac_key, *iv;
+ const br_hash_class *imh;
+ size_t mac_key_len, mac_out_len, iv_len;
+
+ imh = br_ssl_engine_get_hash(cc, mac_id);
+ mac_out_len = (imh->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK;
+ mac_key_len = mac_out_len;
+
+ /*
+ * TLS 1.1+ uses per-record explicit IV, so no IV to generate here.
+ */
+ if (cc->session.version >= BR_TLS11) {
+ iv_len = 0;
+ } else {
+ iv_len = bc_impl->block_size;
+ }
+ compute_key_block(cc, prf_id,
+ mac_key_len + cipher_key_len + iv_len, kb);
+ if (is_client) {
+ mac_key = &kb[0];
+ cipher_key = &kb[mac_key_len << 1];
+ iv = &kb[(mac_key_len + cipher_key_len) << 1];
+ } else {
+ mac_key = &kb[mac_key_len];
+ cipher_key = &kb[(mac_key_len << 1) + cipher_key_len];
+ iv = &kb[((mac_key_len + cipher_key_len) << 1) + iv_len];
+ }
+ if (iv_len == 0) {
+ iv = NULL;
+ }
+ cc->icbc_out->init(&cc->out.cbc.vtable,
+ bc_impl, cipher_key, cipher_key_len,
+ imh, mac_key, mac_key_len, mac_out_len, iv);
+}
+
+/* see inner.h */
+void
+br_ssl_engine_switch_gcm_in(br_ssl_engine_context *cc,
+ int is_client, int prf_id,
+ const br_block_ctr_class *bc_impl, size_t cipher_key_len)
+{
+ unsigned char kb[72];
+ unsigned char *cipher_key, *iv;
+
+ compute_key_block(cc, prf_id, cipher_key_len + 4, kb);
+ if (is_client) {
+ cipher_key = &kb[cipher_key_len];
+ iv = &kb[(cipher_key_len << 1) + 4];
+ } else {
+ cipher_key = &kb[0];
+ iv = &kb[cipher_key_len << 1];
+ }
+ cc->igcm_in->init(&cc->in.gcm.vtable.in,
+ bc_impl, cipher_key, cipher_key_len, cc->ighash, iv);
+ cc->incrypt = 1;
+}
+
+/* see inner.h */
+void
+br_ssl_engine_switch_gcm_out(br_ssl_engine_context *cc,
+ int is_client, int prf_id,
+ const br_block_ctr_class *bc_impl, size_t cipher_key_len)
+{
+ unsigned char kb[72];
+ unsigned char *cipher_key, *iv;
+
+ compute_key_block(cc, prf_id, cipher_key_len + 4, kb);
+ if (is_client) {
+ cipher_key = &kb[0];
+ iv = &kb[cipher_key_len << 1];
+ } else {
+ cipher_key = &kb[cipher_key_len];
+ iv = &kb[(cipher_key_len << 1) + 4];
+ }
+ cc->igcm_out->init(&cc->out.gcm.vtable.out,
+ bc_impl, cipher_key, cipher_key_len, cc->ighash, iv);
+}
--- /dev/null
+/*
+ * 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 inner.h */
+int
+br_ssl_choose_hash(unsigned bf)
+{
+ static const unsigned char pref[] = {
+ br_sha256_ID, br_sha384_ID, br_sha512_ID,
+ br_sha224_ID, br_sha1_ID
+ };
+ size_t u;
+
+ for (u = 0; u < sizeof pref; u ++) {
+ int x;
+
+ x = pref[u];
+ if ((bf >> x) & 1) {
+ return x;
+ }
+ }
+ return 0;
+}
--- /dev/null
+/* 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 uint8_t t0_datablock[];
+
+
+void br_ssl_hs_client_init_main(void *t0ctx);
+
+void br_ssl_hs_client_run(void *t0ctx);
+
+
+
+#include <stddef.h>
+#include <string.h>
+
+#include "inner.h"
+
+/*
+ * This macro evaluates to a pointer to the current engine context.
+ */
+#define ENG ((br_ssl_engine_context *)((unsigned char *)t0ctx - offsetof(br_ssl_engine_context, cpu)))
+
+
+
+
+
+/*
+ * This macro evaluates to a pointer to the client context, under that
+ * specific name. It must be noted that since the engine context is the
+ * first field of the br_ssl_client_context structure ('eng'), then
+ * pointers values of both types are interchangeable, modulo an
+ * appropriate cast. This also means that "adresses" computed as offsets
+ * within the structure work for both kinds of context.
+ */
+#define CTX ((br_ssl_client_context *)ENG)
+
+/*
+ * Generate the pre-master secret for RSA key exchange, and encrypt it
+ * with the server's public key. Returned value is either the encrypted
+ * data length (in bytes), or -x on error, with 'x' being an error code.
+ *
+ * This code assumes that the public key has been already verified (it
+ * was properly obtained by the X.509 engine, and it has the right type,
+ * i.e. it is of type RSA and suitable for encryption).
+ */
+static int
+make_pms_rsa(br_ssl_client_context *ctx, int prf_id)
+{
+ const br_x509_class **xc;
+ const br_x509_pkey *pk;
+ const unsigned char *n;
+ unsigned char *pms;
+ size_t nlen, u;
+
+ xc = ctx->eng.x509ctx;
+ pk = (*xc)->get_pkey(xc);
+
+ /*
+ * Compute actual RSA key length, in case there are leading zeros.
+ */
+ n = pk->key.rsa.n;
+ nlen = pk->key.rsa.nlen;
+ while (nlen > 0 && *n == 0) {
+ n ++;
+ nlen --;
+ }
+
+ /*
+ * We need at least 59 bytes (48 bytes for pre-master secret, and
+ * 11 bytes for the PKCS#1 type 2 padding). Note that the X.509
+ * minimal engine normally blocks RSA keys shorter than 128 bytes,
+ * so this is mostly for public keys provided explicitly by the
+ * caller.
+ */
+ if (nlen < 59) {
+ return -BR_ERR_X509_WEAK_PUBLIC_KEY;
+ }
+ if (nlen > sizeof ctx->eng.pad) {
+ return -BR_ERR_LIMIT_EXCEEDED;
+ }
+
+ /*
+ * Make PMS.
+ */
+ pms = ctx->eng.pad + nlen - 48;
+ br_enc16be(pms, ctx->eng.version_max);
+ br_hmac_drbg_generate(&ctx->eng.rng, pms + 2, 46);
+ br_ssl_engine_compute_master(&ctx->eng, prf_id, pms, 48);
+
+ /*
+ * Apply PKCS#1 type 2 padding.
+ */
+ ctx->eng.pad[0] = 0x00;
+ ctx->eng.pad[1] = 0x02;
+ ctx->eng.pad[nlen - 49] = 0x00;
+ br_hmac_drbg_generate(&ctx->eng.rng, ctx->eng.pad + 2, nlen - 51);
+ for (u = 2; u < nlen - 49; u ++) {
+ while (ctx->eng.pad[u] == 0) {
+ br_hmac_drbg_generate(&ctx->eng.rng,
+ &ctx->eng.pad[u], 1);
+ }
+ }
+
+ /*
+ * Compute RSA encryption.
+ */
+ if (!ctx->irsapub(ctx->eng.pad, nlen, &pk->key.rsa)) {
+ return -BR_ERR_LIMIT_EXCEEDED;
+ }
+ return (int)nlen;
+}
+
+/*
+ * OID for hash functions in RSA signatures.
+ */
+static const unsigned char HASH_OID_SHA1[] = {
+ 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A
+};
+
+static const unsigned char HASH_OID_SHA224[] = {
+ 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04
+};
+
+static const unsigned char HASH_OID_SHA256[] = {
+ 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01
+};
+
+static const unsigned char HASH_OID_SHA384[] = {
+ 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02
+};
+
+static const unsigned char HASH_OID_SHA512[] = {
+ 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03
+};
+
+static const unsigned char *HASH_OID[] = {
+ HASH_OID_SHA1,
+ HASH_OID_SHA224,
+ HASH_OID_SHA256,
+ HASH_OID_SHA384,
+ HASH_OID_SHA512
+};
+
+/*
+ * Check the RSA signature on the ServerKeyExchange message.
+ * hash hash function ID (2 to 6), or 0 for MD5+SHA-1 (with RSA only)
+ * use_rsa non-zero for RSA signature, zero for ECDSA
+ * sig_len signature length (in bytes); signature value is in the pad
+ * Returned value is 0 on success, or an error code.
+ */
+static int
+verify_SKE_sig(br_ssl_client_context *ctx,
+ int hash, int use_rsa, size_t sig_len)
+{
+ const br_x509_class **xc;
+ const br_x509_pkey *pk;
+ br_multihash_context mhc;
+ unsigned char hv[64], head[4];
+ size_t hv_len;
+
+ xc = ctx->eng.x509ctx;
+ pk = (*xc)->get_pkey(xc);
+ br_multihash_zero(&mhc);
+ br_multihash_copyimpl(&mhc, &ctx->eng.mhash);
+ br_multihash_init(&mhc);
+ br_multihash_update(&mhc,
+ ctx->eng.client_random, sizeof ctx->eng.client_random);
+ br_multihash_update(&mhc,
+ ctx->eng.server_random, sizeof ctx->eng.server_random);
+ head[0] = 3;
+ head[1] = 0;
+ head[2] = ctx->eng.ecdhe_curve;
+ head[3] = ctx->eng.ecdhe_point_len;
+ br_multihash_update(&mhc, head, sizeof head);
+ br_multihash_update(&mhc,
+ ctx->eng.ecdhe_point, ctx->eng.ecdhe_point_len);
+ if (hash) {
+ hv_len = br_multihash_out(&mhc, hash, hv);
+ if (hv_len == 0) {
+ return BR_ERR_INVALID_ALGORITHM;
+ }
+ } else {
+ if (!br_multihash_out(&mhc, br_md5_ID, hv)
+ || !br_multihash_out(&mhc, br_sha1_ID, hv + 16))
+ {
+ return BR_ERR_INVALID_ALGORITHM;
+ }
+ hv_len = 36;
+ }
+ if (use_rsa) {
+ unsigned char tmp[64];
+ const unsigned char *hash_oid;
+
+ if (hash) {
+ hash_oid = HASH_OID[hash - 2];
+ } else {
+ hash_oid = NULL;
+ }
+ if (!ctx->irsavrfy(ctx->eng.pad, sig_len,
+ hash_oid, hv_len, &pk->key.rsa, tmp)
+ || memcmp(tmp, hv, hv_len) != 0)
+ {
+ return BR_ERR_BAD_SIGNATURE;
+ }
+ } else {
+ if (!ctx->iecdsa(ctx->eng.iec, hv, hv_len, &pk->key.ec,
+ ctx->eng.pad, sig_len))
+ {
+ return BR_ERR_BAD_SIGNATURE;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Perform client-size ECDH (or ECDHE). The point that should be sent to
+ * the server is written in the pad; returned value is either the point
+ * length (in bytes), or -x on error, with 'x' being an error code.
+ *
+ * The point _from_ the server is taken from ecdhe_point[] if 'ecdhe'
+ * is non-zero, or from the X.509 engine context if 'ecdhe' is zero
+ * (for static ECDH).
+ */
+static int
+make_pms_ecdh(br_ssl_client_context *ctx, unsigned ecdhe, int prf_id)
+{
+ int curve;
+ unsigned char key[66], point[133];
+ const unsigned char *generator, *order, *point_src;
+ size_t glen, olen, point_len;
+ unsigned char mask;
+
+ if (ecdhe) {
+ curve = ctx->eng.ecdhe_curve;
+ point_src = ctx->eng.ecdhe_point;
+ point_len = ctx->eng.ecdhe_point_len;
+ } else {
+ const br_x509_class **xc;
+ const br_x509_pkey *pk;
+
+ xc = ctx->eng.x509ctx;
+ pk = (*xc)->get_pkey(xc);
+ curve = pk->key.ec.curve;
+ point_src = pk->key.ec.q;
+ point_len = pk->key.ec.qlen;
+ }
+ if ((ctx->eng.iec->supported_curves & ((uint32_t)1 << curve)) == 0) {
+ return -BR_ERR_INVALID_ALGORITHM;
+ }
+
+ /*
+ * We need to generate our key, as a non-zero random value which
+ * is lower than the curve order, in a "large enough" range. We
+ * force top bit to 0 and bottom bit to 1, which guarantees that
+ * the value is in the proper range.
+ */
+ order = ctx->eng.iec->order(curve, &olen);
+ mask = 0xFF;
+ while (mask >= order[0]) {
+ mask >>= 1;
+ }
+ br_hmac_drbg_generate(&ctx->eng.rng, key, olen);
+ key[0] &= mask;
+ key[olen - 1] |= 0x01;
+
+ /*
+ * Compute the common ECDH point, whose X coordinate is the
+ * pre-master secret.
+ */
+ generator = ctx->eng.iec->generator(curve, &glen);
+ if (glen != point_len) {
+ return -BR_ERR_INVALID_ALGORITHM;
+ }
+
+ memcpy(point, point_src, glen);
+ if (!ctx->eng.iec->mul(point, glen, key, olen, curve)) {
+ return -BR_ERR_INVALID_ALGORITHM;
+ }
+
+ /*
+ * The pre-master secret is the X coordinate.
+ */
+ br_ssl_engine_compute_master(&ctx->eng, prf_id, point + 1, glen >> 1);
+
+ memcpy(point, generator, glen);
+ if (!ctx->eng.iec->mul(point, glen, key, olen, curve)) {
+ return -BR_ERR_INVALID_ALGORITHM;
+ }
+ memcpy(ctx->eng.pad, point, glen);
+ return (int)glen;
+}
+
+
+
+static const uint8_t t0_datablock[] = {
+ 0x00, 0x00, 0x0A, 0x00, 0x24, 0x00, 0x2F, 0x01, 0x24, 0x00, 0x35, 0x02,
+ 0x24, 0x00, 0x3C, 0x01, 0x44, 0x00, 0x3D, 0x02, 0x44, 0x00, 0x9C, 0x03,
+ 0x04, 0x00, 0x9D, 0x04, 0x05, 0xC0, 0x03, 0x40, 0x24, 0xC0, 0x04, 0x41,
+ 0x24, 0xC0, 0x05, 0x42, 0x24, 0xC0, 0x08, 0x20, 0x24, 0xC0, 0x09, 0x21,
+ 0x24, 0xC0, 0x0A, 0x22, 0x24, 0xC0, 0x0D, 0x30, 0x24, 0xC0, 0x0E, 0x31,
+ 0x24, 0xC0, 0x0F, 0x32, 0x24, 0xC0, 0x12, 0x10, 0x24, 0xC0, 0x13, 0x11,
+ 0x24, 0xC0, 0x14, 0x12, 0x24, 0xC0, 0x23, 0x21, 0x44, 0xC0, 0x24, 0x22,
+ 0x55, 0xC0, 0x25, 0x41, 0x44, 0xC0, 0x26, 0x42, 0x55, 0xC0, 0x27, 0x11,
+ 0x44, 0xC0, 0x28, 0x12, 0x55, 0xC0, 0x29, 0x31, 0x44, 0xC0, 0x2A, 0x32,
+ 0x55, 0xC0, 0x2B, 0x23, 0x04, 0xC0, 0x2C, 0x24, 0x05, 0xC0, 0x2D, 0x43,
+ 0x04, 0xC0, 0x2E, 0x44, 0x05, 0xC0, 0x2F, 0x13, 0x04, 0xC0, 0x30, 0x14,
+ 0x05, 0xC0, 0x31, 0x33, 0x04, 0xC0, 0x32, 0x34, 0x05, 0xCC, 0xA8, 0x15,
+ 0x04, 0xCC, 0xA9, 0x25, 0x04, 0x00, 0x00
+};
+
+static const uint8_t t0_codeblock[] = {
+ 0x00, 0x01, 0x00, 0x0A, 0x00, 0x00, 0x01, 0x00, 0x0C, 0x00, 0x00, 0x01,
+ 0x00, 0x0D, 0x00, 0x00, 0x01, 0x00, 0x0E, 0x00, 0x00, 0x01, 0x01, 0x08,
+ 0x00, 0x00, 0x01, 0x01, 0x09, 0x00, 0x00, 0x01, 0x02, 0x08, 0x00, 0x00,
+ 0x01, 0x02, 0x09, 0x00, 0x00, 0x1A, 0x1A, 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_BAD_CCS), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_BAD_CIPHER_SUITE), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_BAD_COMPRESSION), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_BAD_FINISHED), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_BAD_FRAGLEN), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_BAD_HANDSHAKE), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_BAD_HELLO_DONE), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_BAD_PARAM), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_BAD_SECRENEG), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_BAD_SNI), 0x00, 0x00, 0x01, T0_INT1(BR_ERR_BAD_VERSION),
+ 0x00, 0x00, 0x01, T0_INT1(BR_ERR_EXTRA_EXTENSION), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_INVALID_ALGORITHM), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_LIMIT_EXCEEDED), 0x00, 0x00, 0x01, T0_INT1(BR_ERR_OK),
+ 0x00, 0x00, 0x01, T0_INT1(BR_ERR_OVERSIZED_ID), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_RESUME_MISMATCH), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_UNEXPECTED), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_UNSUPPORTED_VERSION), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, action)), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, alert)), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, application_data)), 0x00, 0x00,
+ 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, session) + offsetof(br_ssl_session_parameters, cipher_suite)),
+ 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, client_random)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(br_ssl_engine_context, close_received)), 0x00,
+ 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, ecdhe_curve)),
+ 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, ecdhe_point)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(br_ssl_engine_context, ecdhe_point_len)), 0x00,
+ 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, log_max_frag_len)),
+ 0x00, 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, pad)), 0x00,
+ 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, record_type_in)),
+ 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, record_type_out)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(br_ssl_engine_context, reneg)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(br_ssl_engine_context, saved_finished)), 0x00,
+ 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, server_name)),
+ 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, server_random)), 0x00, 0x00,
+ 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, session) + offsetof(br_ssl_session_parameters, session_id)),
+ 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, session) + offsetof(br_ssl_session_parameters, session_id_len)),
+ 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, shutdown_recv)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(br_ssl_engine_context, suites_buf)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(br_ssl_engine_context, suites_num)), 0x00, 0x00,
+ 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, session) + offsetof(br_ssl_session_parameters, version)),
+ 0x00, 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, version_in)),
+ 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, version_max)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(br_ssl_engine_context, version_min)), 0x00,
+ 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, version_out)),
+ 0x00, 0x00, 0x09, 0x1B, 0x40, 0x06, 0x02, 0x50, 0x1C, 0x00, 0x00, 0x06,
+ 0x08, 0x1E, 0x0D, 0x05, 0x02, 0x59, 0x1C, 0x04, 0x01, 0x2B, 0x00, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x03, 0x00, 0x79, 0x1B, 0x46, 0x32, 0x7D, 0x1B,
+ 0x05, 0x04, 0x48, 0x01, 0x00, 0x00, 0x02, 0x00, 0x0D, 0x06, 0x02, 0x7D,
+ 0x00, 0x46, 0x04, 0x6B, 0x00, 0x06, 0x02, 0x50, 0x1C, 0x00, 0x00, 0x1B,
+ 0x6A, 0x32, 0x05, 0x03, 0x01, 0x0C, 0x08, 0x32, 0x5F, 0x1E, 0x81, 0x0A,
+ 0x15, 0x66, 0x01, 0x0C, 0x22, 0x00, 0x00, 0x1B, 0x16, 0x01, 0x08, 0x0B,
+ 0x32, 0x44, 0x16, 0x08, 0x00, 0x01, 0x03, 0x00, 0x01, 0x00, 0x5E, 0x2C,
+ 0x1D, 0x13, 0x26, 0x06, 0x08, 0x02, 0x00, 0x81, 0x29, 0x03, 0x00, 0x04,
+ 0x74, 0x01, 0x00, 0x81, 0x21, 0x02, 0x00, 0x1B, 0x13, 0x11, 0x06, 0x02,
+ 0x57, 0x1C, 0x81, 0x29, 0x04, 0x75, 0x01, 0x01, 0x00, 0x5E, 0x2C, 0x01,
+ 0x16, 0x68, 0x2C, 0x25, 0x81, 0x2D, 0x1D, 0x81, 0x11, 0x06, 0x0B, 0x01,
+ 0x7F, 0x81, 0x0D, 0x01, 0x7F, 0x81, 0x2C, 0x04, 0x80, 0x42, 0x81, 0x0E,
+ 0x5F, 0x1E, 0x81, 0x01, 0x01, T0_INT1(BR_KEYTYPE_SIGN), 0x11, 0x06,
+ 0x02, 0x81, 0x12, 0x81, 0x15, 0x1B, 0x01, 0x0D, 0x0D, 0x06, 0x09, 0x1A,
+ 0x81, 0x14, 0x81, 0x15, 0x01, 0x7F, 0x04, 0x02, 0x01, 0x00, 0x03, 0x00,
+ 0x01, 0x0E, 0x0D, 0x05, 0x02, 0x5A, 0x1C, 0x06, 0x02, 0x4F, 0x1C, 0x24,
+ 0x06, 0x02, 0x5A, 0x1C, 0x02, 0x00, 0x06, 0x02, 0x81, 0x33, 0x81, 0x2E,
+ 0x01, 0x7F, 0x81, 0x2C, 0x01, 0x7F, 0x81, 0x0D, 0x01, 0x01, 0x5E, 0x2C,
+ 0x01, 0x17, 0x68, 0x2C, 0x00, 0x00, 0x28, 0x28, 0x00, 0x00, 0x7A, 0x01,
+ 0x0C, 0x10, 0x01, 0x00, 0x28, 0x0D, 0x06, 0x05, 0x1A, 0x01,
+ T0_INT1(BR_KEYTYPE_RSA | BR_KEYTYPE_KEYX), 0x04, 0x30, 0x01, 0x01,
+ 0x28, 0x0D, 0x06, 0x05, 0x1A, 0x01,
+ T0_INT1(BR_KEYTYPE_RSA | BR_KEYTYPE_SIGN), 0x04, 0x25, 0x01, 0x02,
+ 0x28, 0x0D, 0x06, 0x05, 0x1A, 0x01,
+ T0_INT1(BR_KEYTYPE_EC | BR_KEYTYPE_SIGN), 0x04, 0x1A, 0x01, 0x03,
+ 0x28, 0x0D, 0x06, 0x05, 0x1A, 0x01,
+ T0_INT1(BR_KEYTYPE_EC | BR_KEYTYPE_KEYX), 0x04, 0x0F, 0x01, 0x04,
+ 0x28, 0x0D, 0x06, 0x05, 0x1A, 0x01,
+ T0_INT1(BR_KEYTYPE_EC | BR_KEYTYPE_KEYX), 0x04, 0x04, 0x01, 0x00,
+ 0x32, 0x1A, 0x00, 0x00, 0x65, 0x1F, 0x01, 0x0E, 0x0D, 0x06, 0x04, 0x01,
+ 0x00, 0x04, 0x02, 0x01, 0x05, 0x00, 0x00, 0x2E, 0x06, 0x04, 0x01, 0x06,
+ 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x69, 0x1F, 0x1B, 0x06, 0x08, 0x01,
+ 0x01, 0x09, 0x01, 0x11, 0x07, 0x04, 0x03, 0x1A, 0x01, 0x05, 0x00, 0x01,
+ 0x2F, 0x03, 0x00, 0x1A, 0x01, 0x00, 0x31, 0x06, 0x03, 0x02, 0x00, 0x08,
+ 0x30, 0x06, 0x03, 0x02, 0x00, 0x08, 0x1B, 0x06, 0x06, 0x01, 0x01, 0x0B,
+ 0x01, 0x06, 0x08, 0x00, 0x00, 0x6B, 0x2D, 0x1B, 0x06, 0x03, 0x01, 0x09,
+ 0x08, 0x00, 0x01, 0x2E, 0x1B, 0x06, 0x1E, 0x01, 0x00, 0x03, 0x00, 0x1B,
+ 0x06, 0x0E, 0x1B, 0x01, 0x01, 0x11, 0x02, 0x00, 0x08, 0x03, 0x00, 0x01,
+ 0x01, 0x10, 0x04, 0x6F, 0x1A, 0x02, 0x00, 0x01, 0x01, 0x0B, 0x01, 0x06,
+ 0x08, 0x00, 0x00, 0x7F, 0x81, 0x28, 0x1B, 0x01, 0x07, 0x11, 0x01, 0x00,
+ 0x28, 0x0D, 0x06, 0x09, 0x1A, 0x01, 0x10, 0x11, 0x06, 0x01, 0x7F, 0x04,
+ 0x2C, 0x01, 0x01, 0x28, 0x0D, 0x06, 0x23, 0x1A, 0x1A, 0x01, 0x00, 0x5E,
+ 0x2C, 0x81, 0x10, 0x69, 0x1F, 0x01, 0x01, 0x0D, 0x06, 0x11, 0x1D, 0x13,
+ 0x26, 0x06, 0x05, 0x81, 0x28, 0x1A, 0x04, 0x77, 0x01, 0x80, 0x64, 0x81,
+ 0x21, 0x04, 0x01, 0x7F, 0x04, 0x03, 0x5A, 0x1C, 0x1A, 0x04, 0xFF, 0x3C,
+ 0x01, 0x1B, 0x03, 0x00, 0x09, 0x1B, 0x40, 0x06, 0x02, 0x50, 0x1C, 0x02,
+ 0x00, 0x00, 0x00, 0x7A, 0x01, 0x0F, 0x11, 0x00, 0x00, 0x5D, 0x1F, 0x01,
+ 0x00, 0x28, 0x0D, 0x06, 0x10, 0x1A, 0x1B, 0x01, 0x01, 0x0C, 0x06, 0x03,
+ 0x1A, 0x01, 0x02, 0x5D, 0x2C, 0x01, 0x00, 0x04, 0x15, 0x01, 0x01, 0x28,
+ 0x0D, 0x06, 0x09, 0x1A, 0x01, 0x00, 0x5D, 0x2C, 0x42, 0x00, 0x04, 0x06,
+ 0x01, 0x82, 0x00, 0x08, 0x1C, 0x1A, 0x00, 0x00, 0x01, 0x00, 0x20, 0x06,
+ 0x06, 0x2A, 0x81, 0x0B, 0x27, 0x04, 0x77, 0x1B, 0x06, 0x04, 0x01, 0x01,
+ 0x6F, 0x2C, 0x00, 0x00, 0x20, 0x06, 0x0B, 0x67, 0x1F, 0x01, 0x14, 0x0C,
+ 0x06, 0x02, 0x5A, 0x1C, 0x04, 0x12, 0x81, 0x28, 0x01, 0x07, 0x11, 0x1B,
+ 0x01, 0x02, 0x0C, 0x06, 0x06, 0x06, 0x02, 0x5A, 0x1C, 0x04, 0x6F, 0x1A,
+ 0x81, 0x1E, 0x01, 0x01, 0x0C, 0x24, 0x27, 0x06, 0x02, 0x49, 0x1C, 0x1B,
+ 0x01, 0x01, 0x81, 0x24, 0x26, 0x81, 0x0F, 0x00, 0x01, 0x81, 0x15, 0x01,
+ 0x0B, 0x0D, 0x05, 0x02, 0x5A, 0x1C, 0x5F, 0x1E, 0x81, 0x01, 0x3F, 0x81,
+ 0x1C, 0x81, 0x09, 0x1B, 0x06, 0x26, 0x81, 0x1C, 0x81, 0x09, 0x1B, 0x3E,
+ 0x1B, 0x06, 0x19, 0x1B, 0x01, 0x82, 0x00, 0x0E, 0x06, 0x05, 0x01, 0x82,
+ 0x00, 0x04, 0x01, 0x1B, 0x03, 0x00, 0x66, 0x02, 0x00, 0x81, 0x13, 0x02,
+ 0x00, 0x3B, 0x04, 0x64, 0x7B, 0x3C, 0x04, 0x57, 0x7B, 0x7B, 0x3D, 0x1B,
+ 0x06, 0x01, 0x1C, 0x1A, 0x00, 0x00, 0x7C, 0x81, 0x15, 0x01, 0x14, 0x0C,
+ 0x06, 0x02, 0x5A, 0x1C, 0x66, 0x01, 0x0C, 0x08, 0x01, 0x0C, 0x81, 0x13,
+ 0x7B, 0x66, 0x1B, 0x01, 0x0C, 0x08, 0x01, 0x0C, 0x21, 0x05, 0x02, 0x4C,
+ 0x1C, 0x00, 0x00, 0x81, 0x16, 0x06, 0x02, 0x5A, 0x1C, 0x06, 0x02, 0x4E,
+ 0x1C, 0x00, 0x09, 0x81, 0x15, 0x01, 0x02, 0x0D, 0x05, 0x02, 0x5A, 0x1C,
+ 0x81, 0x1B, 0x03, 0x00, 0x02, 0x00, 0x75, 0x1E, 0x0A, 0x02, 0x00, 0x74,
+ 0x1E, 0x0E, 0x27, 0x06, 0x02, 0x5B, 0x1C, 0x02, 0x00, 0x73, 0x1E, 0x0C,
+ 0x06, 0x02, 0x53, 0x1C, 0x02, 0x00, 0x76, 0x2B, 0x6C, 0x01, 0x20, 0x81,
+ 0x13, 0x01, 0x00, 0x03, 0x01, 0x81, 0x1D, 0x03, 0x02, 0x02, 0x02, 0x01,
+ 0x20, 0x0E, 0x06, 0x02, 0x58, 0x1C, 0x66, 0x02, 0x02, 0x81, 0x13, 0x02,
+ 0x02, 0x6E, 0x1F, 0x0D, 0x02, 0x02, 0x01, 0x00, 0x0E, 0x11, 0x06, 0x0B,
+ 0x6D, 0x66, 0x02, 0x02, 0x21, 0x06, 0x04, 0x01, 0x7F, 0x03, 0x01, 0x6D,
+ 0x66, 0x02, 0x02, 0x22, 0x02, 0x02, 0x6E, 0x2C, 0x02, 0x00, 0x72, 0x02,
+ 0x01, 0x78, 0x81, 0x1B, 0x1B, 0x81, 0x1F, 0x40, 0x06, 0x02, 0x4A, 0x1C,
+ 0x5F, 0x02, 0x01, 0x78, 0x81, 0x1D, 0x06, 0x02, 0x4B, 0x1C, 0x1B, 0x06,
+ 0x81, 0x3D, 0x81, 0x1B, 0x81, 0x09, 0x81, 0x06, 0x03, 0x03, 0x81, 0x04,
+ 0x03, 0x04, 0x81, 0x02, 0x03, 0x05, 0x81, 0x05, 0x03, 0x06, 0x81, 0x07,
+ 0x03, 0x07, 0x81, 0x03, 0x03, 0x08, 0x1B, 0x06, 0x81, 0x0B, 0x81, 0x1B,
+ 0x01, 0x00, 0x28, 0x0D, 0x06, 0x10, 0x1A, 0x02, 0x03, 0x05, 0x02, 0x54,
+ 0x1C, 0x01, 0x00, 0x03, 0x03, 0x81, 0x1A, 0x04, 0x80, 0x70, 0x01, 0x01,
+ 0x28, 0x0D, 0x06, 0x10, 0x1A, 0x02, 0x05, 0x05, 0x02, 0x54, 0x1C, 0x01,
+ 0x00, 0x03, 0x05, 0x81, 0x18, 0x04, 0x80, 0x5A, 0x01, 0x83, 0xFE, 0x01,
+ 0x28, 0x0D, 0x06, 0x10, 0x1A, 0x02, 0x04, 0x05, 0x02, 0x54, 0x1C, 0x01,
+ 0x00, 0x03, 0x04, 0x81, 0x19, 0x04, 0x80, 0x42, 0x01, 0x0D, 0x28, 0x0D,
+ 0x06, 0x0F, 0x1A, 0x02, 0x06, 0x05, 0x02, 0x54, 0x1C, 0x01, 0x00, 0x03,
+ 0x06, 0x81, 0x17, 0x04, 0x2D, 0x01, 0x0A, 0x28, 0x0D, 0x06, 0x0F, 0x1A,
+ 0x02, 0x07, 0x05, 0x02, 0x54, 0x1C, 0x01, 0x00, 0x03, 0x07, 0x81, 0x17,
+ 0x04, 0x18, 0x01, 0x0B, 0x28, 0x0D, 0x06, 0x0F, 0x1A, 0x02, 0x08, 0x05,
+ 0x02, 0x54, 0x1C, 0x01, 0x00, 0x03, 0x08, 0x81, 0x17, 0x04, 0x03, 0x54,
+ 0x1C, 0x1A, 0x04, 0xFE, 0x71, 0x02, 0x04, 0x06, 0x0D, 0x02, 0x04, 0x01,
+ 0x05, 0x0E, 0x06, 0x02, 0x51, 0x1C, 0x01, 0x01, 0x69, 0x2C, 0x7B, 0x7B,
+ 0x02, 0x01, 0x00, 0x04, 0x81, 0x15, 0x01, 0x0C, 0x0D, 0x05, 0x02, 0x5A,
+ 0x1C, 0x81, 0x1D, 0x01, 0x03, 0x0D, 0x05, 0x02, 0x55, 0x1C, 0x81, 0x1B,
+ 0x1B, 0x62, 0x2C, 0x1B, 0x01, 0x20, 0x0F, 0x06, 0x02, 0x55, 0x1C, 0x2E,
+ 0x32, 0x10, 0x01, 0x01, 0x11, 0x05, 0x02, 0x55, 0x1C, 0x81, 0x1D, 0x1B,
+ 0x01, 0x81, 0x05, 0x0E, 0x06, 0x02, 0x55, 0x1C, 0x1B, 0x64, 0x2C, 0x63,
+ 0x32, 0x81, 0x13, 0x72, 0x1E, 0x01, 0x86, 0x03, 0x0F, 0x03, 0x00, 0x5F,
+ 0x1E, 0x81, 0x26, 0x03, 0x01, 0x01, 0x02, 0x03, 0x02, 0x02, 0x00, 0x06,
+ 0x23, 0x81, 0x1D, 0x1B, 0x1B, 0x01, 0x02, 0x0A, 0x32, 0x01, 0x06, 0x0E,
+ 0x27, 0x06, 0x02, 0x55, 0x1C, 0x03, 0x02, 0x81, 0x1D, 0x02, 0x01, 0x01,
+ 0x01, 0x0B, 0x01, 0x03, 0x08, 0x0D, 0x05, 0x02, 0x55, 0x1C, 0x04, 0x08,
+ 0x02, 0x01, 0x06, 0x04, 0x01, 0x00, 0x03, 0x02, 0x81, 0x1B, 0x1B, 0x03,
+ 0x03, 0x1B, 0x01, 0x84, 0x00, 0x0E, 0x06, 0x02, 0x56, 0x1C, 0x66, 0x32,
+ 0x81, 0x13, 0x02, 0x02, 0x02, 0x01, 0x02, 0x03, 0x38, 0x1B, 0x06, 0x01,
+ 0x1C, 0x1A, 0x7B, 0x00, 0x02, 0x03, 0x00, 0x03, 0x01, 0x02, 0x00, 0x77,
+ 0x02, 0x01, 0x02, 0x00, 0x29, 0x1B, 0x01, 0x00, 0x0D, 0x06, 0x02, 0x48,
+ 0x00, 0x81, 0x2A, 0x04, 0x73, 0x00, 0x1B, 0x06, 0x05, 0x81, 0x1D, 0x1A,
+ 0x04, 0x78, 0x1A, 0x00, 0x00, 0x81, 0x16, 0x1B, 0x42, 0x06, 0x07, 0x1A,
+ 0x06, 0x02, 0x4E, 0x1C, 0x04, 0x73, 0x00, 0x00, 0x81, 0x1E, 0x01, 0x03,
+ 0x81, 0x1C, 0x32, 0x1A, 0x32, 0x00, 0x00, 0x81, 0x1B, 0x81, 0x22, 0x00,
+ 0x00, 0x81, 0x1B, 0x01, 0x01, 0x0D, 0x05, 0x02, 0x4D, 0x1C, 0x81, 0x1D,
+ 0x01, 0x08, 0x08, 0x65, 0x1F, 0x0D, 0x05, 0x02, 0x4D, 0x1C, 0x00, 0x00,
+ 0x81, 0x1B, 0x69, 0x1F, 0x05, 0x16, 0x01, 0x01, 0x0D, 0x05, 0x02, 0x51,
+ 0x1C, 0x81, 0x1D, 0x01, 0x00, 0x0D, 0x05, 0x02, 0x51, 0x1C, 0x01, 0x02,
+ 0x69, 0x2C, 0x04, 0x1E, 0x01, 0x19, 0x0D, 0x05, 0x02, 0x51, 0x1C, 0x81,
+ 0x1D, 0x01, 0x18, 0x0D, 0x05, 0x02, 0x51, 0x1C, 0x66, 0x01, 0x18, 0x81,
+ 0x13, 0x6A, 0x66, 0x01, 0x18, 0x21, 0x05, 0x02, 0x51, 0x1C, 0x00, 0x00,
+ 0x81, 0x1B, 0x06, 0x02, 0x52, 0x1C, 0x00, 0x00, 0x01, 0x02, 0x77, 0x81,
+ 0x1E, 0x01, 0x08, 0x0B, 0x81, 0x1E, 0x08, 0x00, 0x00, 0x01, 0x03, 0x77,
+ 0x81, 0x1E, 0x01, 0x08, 0x0B, 0x81, 0x1E, 0x08, 0x01, 0x08, 0x0B, 0x81,
+ 0x1E, 0x08, 0x00, 0x00, 0x01, 0x01, 0x77, 0x81, 0x1E, 0x00, 0x00, 0x2A,
+ 0x1B, 0x40, 0x05, 0x01, 0x00, 0x1A, 0x81, 0x2A, 0x04, 0x75, 0x02, 0x03,
+ 0x00, 0x71, 0x1F, 0x03, 0x01, 0x01, 0x00, 0x1B, 0x02, 0x01, 0x0A, 0x06,
+ 0x10, 0x1B, 0x01, 0x01, 0x0B, 0x70, 0x08, 0x1E, 0x02, 0x00, 0x0D, 0x06,
+ 0x01, 0x00, 0x44, 0x04, 0x6A, 0x1A, 0x01, 0x7F, 0x00, 0x00, 0x01, 0x15,
+ 0x68, 0x2C, 0x32, 0x3A, 0x1A, 0x3A, 0x1A, 0x1D, 0x00, 0x00, 0x01, 0x01,
+ 0x32, 0x81, 0x20, 0x00, 0x00, 0x32, 0x28, 0x77, 0x32, 0x1B, 0x06, 0x06,
+ 0x81, 0x1E, 0x1A, 0x45, 0x04, 0x77, 0x1A, 0x00, 0x00, 0x7A, 0x41, 0x00,
+ 0x02, 0x03, 0x00, 0x5F, 0x1E, 0x7A, 0x03, 0x01, 0x02, 0x01, 0x01, 0x0F,
+ 0x11, 0x02, 0x01, 0x01, 0x04, 0x10, 0x01, 0x0F, 0x11, 0x02, 0x01, 0x01,
+ 0x08, 0x10, 0x01, 0x0F, 0x11, 0x01, 0x00, 0x28, 0x0D, 0x06, 0x10, 0x1A,
+ 0x01, 0x00, 0x01, 0x18, 0x02, 0x00, 0x06, 0x03, 0x35, 0x04, 0x01, 0x36,
+ 0x04, 0x80, 0x56, 0x01, 0x01, 0x28, 0x0D, 0x06, 0x10, 0x1A, 0x01, 0x01,
+ 0x01, 0x10, 0x02, 0x00, 0x06, 0x03, 0x35, 0x04, 0x01, 0x36, 0x04, 0x80,
+ 0x40, 0x01, 0x02, 0x28, 0x0D, 0x06, 0x0F, 0x1A, 0x01, 0x01, 0x01, 0x20,
+ 0x02, 0x00, 0x06, 0x03, 0x35, 0x04, 0x01, 0x36, 0x04, 0x2B, 0x01, 0x03,
+ 0x28, 0x0D, 0x06, 0x0E, 0x1A, 0x1A, 0x01, 0x10, 0x02, 0x00, 0x06, 0x03,
+ 0x33, 0x04, 0x01, 0x34, 0x04, 0x17, 0x01, 0x04, 0x28, 0x0D, 0x06, 0x0E,
+ 0x1A, 0x1A, 0x01, 0x20, 0x02, 0x00, 0x06, 0x03, 0x33, 0x04, 0x01, 0x34,
+ 0x04, 0x03, 0x50, 0x1C, 0x1A, 0x00, 0x00, 0x7A, 0x01, 0x0C, 0x10, 0x1B,
+ 0x43, 0x32, 0x01, 0x03, 0x0A, 0x11, 0x00, 0x00, 0x7A, 0x01, 0x0C, 0x10,
+ 0x01, 0x01, 0x0D, 0x00, 0x00, 0x7A, 0x01, 0x0C, 0x10, 0x42, 0x00, 0x00,
+ 0x14, 0x01, 0x00, 0x5C, 0x1F, 0x1B, 0x06, 0x1F, 0x01, 0x01, 0x28, 0x0D,
+ 0x06, 0x06, 0x1A, 0x01, 0x00, 0x7E, 0x04, 0x11, 0x01, 0x02, 0x28, 0x0D,
+ 0x06, 0x0A, 0x1A, 0x5E, 0x1F, 0x06, 0x03, 0x01, 0x10, 0x27, 0x04, 0x01,
+ 0x1A, 0x04, 0x01, 0x1A, 0x61, 0x1F, 0x05, 0x34, 0x20, 0x06, 0x31, 0x67,
+ 0x1F, 0x01, 0x14, 0x28, 0x0D, 0x06, 0x06, 0x1A, 0x01, 0x02, 0x27, 0x04,
+ 0x23, 0x01, 0x15, 0x28, 0x0D, 0x06, 0x0A, 0x1A, 0x81, 0x0C, 0x06, 0x03,
+ 0x01, 0x7F, 0x7E, 0x04, 0x13, 0x01, 0x16, 0x28, 0x0D, 0x06, 0x06, 0x1A,
+ 0x01, 0x01, 0x27, 0x04, 0x07, 0x1A, 0x01, 0x04, 0x27, 0x01, 0x00, 0x1A,
+ 0x13, 0x06, 0x03, 0x01, 0x08, 0x27, 0x00, 0x00, 0x14, 0x1B, 0x05, 0x10,
+ 0x20, 0x06, 0x0D, 0x67, 0x1F, 0x01, 0x15, 0x0D, 0x06, 0x05, 0x1A, 0x81,
+ 0x0C, 0x04, 0x01, 0x17, 0x00, 0x00, 0x81, 0x28, 0x01, 0x07, 0x11, 0x01,
+ 0x01, 0x0E, 0x06, 0x02, 0x5A, 0x1C, 0x00, 0x01, 0x03, 0x00, 0x1D, 0x13,
+ 0x06, 0x05, 0x02, 0x00, 0x68, 0x2C, 0x00, 0x81, 0x28, 0x1A, 0x04, 0x73,
+ 0x00, 0x01, 0x14, 0x81, 0x2B, 0x01, 0x01, 0x81, 0x37, 0x1D, 0x1B, 0x01,
+ 0x00, 0x81, 0x24, 0x01, 0x16, 0x81, 0x2B, 0x81, 0x2F, 0x1D, 0x00, 0x01,
+ 0x81, 0x04, 0x81, 0x06, 0x08, 0x81, 0x02, 0x08, 0x81, 0x05, 0x08, 0x81,
+ 0x07, 0x08, 0x81, 0x03, 0x08, 0x03, 0x00, 0x01, 0x01, 0x81, 0x37, 0x01,
+ 0x27, 0x6E, 0x1F, 0x08, 0x71, 0x1F, 0x01, 0x01, 0x0B, 0x08, 0x02, 0x00,
+ 0x06, 0x04, 0x46, 0x02, 0x00, 0x08, 0x81, 0x36, 0x74, 0x1E, 0x81, 0x35,
+ 0x60, 0x01, 0x04, 0x12, 0x60, 0x01, 0x04, 0x08, 0x01, 0x1C, 0x23, 0x60,
+ 0x01, 0x20, 0x81, 0x30, 0x6D, 0x6E, 0x1F, 0x81, 0x32, 0x71, 0x1F, 0x1B,
+ 0x01, 0x01, 0x0B, 0x81, 0x35, 0x70, 0x32, 0x1B, 0x06, 0x11, 0x45, 0x28,
+ 0x1E, 0x1B, 0x81, 0x23, 0x05, 0x02, 0x4A, 0x1C, 0x81, 0x35, 0x32, 0x46,
+ 0x32, 0x04, 0x6C, 0x48, 0x01, 0x01, 0x81, 0x37, 0x01, 0x00, 0x81, 0x37,
+ 0x02, 0x00, 0x06, 0x81, 0x2E, 0x02, 0x00, 0x81, 0x35, 0x81, 0x04, 0x06,
+ 0x12, 0x01, 0x83, 0xFE, 0x01, 0x81, 0x35, 0x6A, 0x81, 0x04, 0x01, 0x04,
+ 0x09, 0x1B, 0x81, 0x35, 0x45, 0x81, 0x32, 0x81, 0x06, 0x06, 0x1C, 0x01,
+ 0x00, 0x81, 0x35, 0x6B, 0x81, 0x06, 0x01, 0x04, 0x09, 0x1B, 0x81, 0x35,
+ 0x01, 0x02, 0x09, 0x1B, 0x81, 0x35, 0x01, 0x00, 0x81, 0x37, 0x01, 0x03,
+ 0x09, 0x81, 0x31, 0x81, 0x02, 0x06, 0x0F, 0x01, 0x01, 0x81, 0x35, 0x01,
+ 0x01, 0x81, 0x35, 0x65, 0x1F, 0x01, 0x08, 0x09, 0x81, 0x37, 0x81, 0x05,
+ 0x06, 0x1F, 0x01, 0x0D, 0x81, 0x35, 0x81, 0x05, 0x01, 0x04, 0x09, 0x1B,
+ 0x81, 0x35, 0x01, 0x02, 0x09, 0x81, 0x35, 0x30, 0x06, 0x04, 0x01, 0x03,
+ 0x81, 0x34, 0x31, 0x06, 0x04, 0x01, 0x01, 0x81, 0x34, 0x81, 0x07, 0x1B,
+ 0x06, 0x27, 0x01, 0x0A, 0x81, 0x35, 0x01, 0x04, 0x09, 0x1B, 0x81, 0x35,
+ 0x47, 0x81, 0x35, 0x2E, 0x01, 0x00, 0x1B, 0x01, 0x20, 0x0A, 0x06, 0x0E,
+ 0x81, 0x00, 0x10, 0x01, 0x01, 0x11, 0x06, 0x03, 0x1B, 0x81, 0x35, 0x44,
+ 0x04, 0x6C, 0x48, 0x04, 0x01, 0x1A, 0x81, 0x03, 0x06, 0x0D, 0x01, 0x0B,
+ 0x81, 0x35, 0x01, 0x02, 0x81, 0x35, 0x01, 0x82, 0x00, 0x81, 0x35, 0x00,
+ 0x00, 0x01, 0x10, 0x81, 0x37, 0x5F, 0x1E, 0x1B, 0x81, 0x27, 0x06, 0x10,
+ 0x81, 0x0A, 0x19, 0x1B, 0x46, 0x81, 0x36, 0x1B, 0x81, 0x35, 0x66, 0x32,
+ 0x81, 0x30, 0x04, 0x12, 0x1B, 0x81, 0x25, 0x32, 0x81, 0x0A, 0x18, 0x1B,
+ 0x44, 0x81, 0x36, 0x1B, 0x81, 0x37, 0x66, 0x32, 0x81, 0x30, 0x00, 0x00,
+ 0x7C, 0x01, 0x14, 0x81, 0x37, 0x01, 0x0C, 0x81, 0x36, 0x66, 0x01, 0x0C,
+ 0x81, 0x30, 0x00, 0x00, 0x39, 0x1B, 0x01, 0x00, 0x0D, 0x06, 0x02, 0x48,
+ 0x00, 0x81, 0x28, 0x1A, 0x04, 0x72, 0x00, 0x1B, 0x81, 0x35, 0x81, 0x30,
+ 0x00, 0x00, 0x1B, 0x81, 0x37, 0x81, 0x30, 0x00, 0x00, 0x01, 0x0B, 0x81,
+ 0x37, 0x01, 0x03, 0x81, 0x36, 0x01, 0x00, 0x81, 0x36, 0x00, 0x01, 0x03,
+ 0x00, 0x2F, 0x1A, 0x1B, 0x01, 0x10, 0x11, 0x06, 0x08, 0x01, 0x04, 0x81,
+ 0x37, 0x02, 0x00, 0x81, 0x37, 0x1B, 0x01, 0x08, 0x11, 0x06, 0x08, 0x01,
+ 0x03, 0x81, 0x37, 0x02, 0x00, 0x81, 0x37, 0x1B, 0x01, 0x20, 0x11, 0x06,
+ 0x08, 0x01, 0x05, 0x81, 0x37, 0x02, 0x00, 0x81, 0x37, 0x1B, 0x01, 0x80,
+ 0x40, 0x11, 0x06, 0x08, 0x01, 0x06, 0x81, 0x37, 0x02, 0x00, 0x81, 0x37,
+ 0x01, 0x04, 0x11, 0x06, 0x08, 0x01, 0x02, 0x81, 0x37, 0x02, 0x00, 0x81,
+ 0x37, 0x00, 0x00, 0x1B, 0x01, 0x08, 0x37, 0x81, 0x37, 0x81, 0x37, 0x00,
+ 0x00, 0x1B, 0x01, 0x10, 0x37, 0x81, 0x37, 0x81, 0x35, 0x00, 0x00, 0x1B,
+ 0x3A, 0x06, 0x02, 0x1A, 0x00, 0x81, 0x28, 0x1A, 0x04, 0x75
+};
+
+static const uint16_t t0_caddr[] = {
+ 0,
+ 5,
+ 10,
+ 15,
+ 20,
+ 25,
+ 30,
+ 35,
+ 40,
+ 44,
+ 48,
+ 52,
+ 56,
+ 60,
+ 64,
+ 68,
+ 72,
+ 76,
+ 80,
+ 84,
+ 88,
+ 92,
+ 96,
+ 100,
+ 104,
+ 108,
+ 112,
+ 116,
+ 120,
+ 125,
+ 130,
+ 135,
+ 140,
+ 145,
+ 150,
+ 155,
+ 160,
+ 165,
+ 170,
+ 175,
+ 180,
+ 185,
+ 190,
+ 195,
+ 200,
+ 205,
+ 210,
+ 215,
+ 220,
+ 225,
+ 230,
+ 235,
+ 240,
+ 245,
+ 250,
+ 255,
+ 264,
+ 277,
+ 281,
+ 306,
+ 312,
+ 332,
+ 343,
+ 380,
+ 483,
+ 487,
+ 552,
+ 567,
+ 578,
+ 596,
+ 625,
+ 635,
+ 671,
+ 741,
+ 755,
+ 761,
+ 808,
+ 828,
+ 881,
+ 950,
+ 983,
+ 995,
+ 1320,
+ 1477,
+ 1502,
+ 1513,
+ 1528,
+ 1539,
+ 1545,
+ 1568,
+ 1628,
+ 1636,
+ 1649,
+ 1668,
+ 1675,
+ 1687,
+ 1722,
+ 1734,
+ 1741,
+ 1757,
+ 1761,
+ 1899,
+ 1912,
+ 1921,
+ 1928,
+ 2032,
+ 2054,
+ 2068,
+ 2085,
+ 2108,
+ 2397,
+ 2444,
+ 2460,
+ 2475,
+ 2482,
+ 2489,
+ 2503,
+ 2579,
+ 2589,
+ 2599
+};
+
+#define T0_INTERPRETED 64
+
+#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_ssl_hs_client_init_main, 136)
+
+void
+br_ssl_hs_client_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() break
+
+ dp = ((t0_context *)t0ctx)->dp;
+ rp = ((t0_context *)t0ctx)->rp;
+ ip = ((t0_context *)t0ctx)->ip;
+ for (;;) {
+ uint32_t t0x;
+
+ t0x = t0_parse7E_unsigned(&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: {
+ /* - */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a - b);
+
+ }
+ 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: {
+ /* bzero */
+
+ size_t len = (size_t)T0_POP();
+ void *addr = (unsigned char *)ENG + (size_t)T0_POP();
+ memset(addr, 0, len);
+
+ }
+ break;
+ case 19: {
+ /* can-output? */
+
+ T0_PUSHi(-(ENG->hlen_out > 0));
+
+ }
+ break;
+ case 20: {
+ /* co */
+ T0_CO();
+ }
+ break;
+ case 21: {
+ /* compute-Finished-inner */
+
+ int prf_id = T0_POP();
+ int from_client = T0_POPi();
+ unsigned char seed[48];
+ size_t seed_len;
+
+ br_tls_prf_impl prf = br_ssl_engine_get_PRF(ENG, prf_id);
+ if (ENG->session.version >= BR_TLS12) {
+ seed_len = br_multihash_out(&ENG->mhash, prf_id, seed);
+ } else {
+ br_multihash_out(&ENG->mhash, br_md5_ID, seed);
+ br_multihash_out(&ENG->mhash, br_sha1_ID, seed + 16);
+ seed_len = 36;
+ }
+ prf(ENG->pad, 12, ENG->session.master_secret,
+ sizeof ENG->session.master_secret,
+ from_client ? "client finished" : "server finished",
+ seed, seed_len);
+
+ }
+ break;
+ case 22: {
+ /* data-get8 */
+
+ size_t addr = T0_POP();
+ T0_PUSH(t0_datablock[addr]);
+
+ }
+ break;
+ case 23: {
+ /* discard-input */
+
+ ENG->hlen_in = 0;
+
+ }
+ break;
+ case 24: {
+ /* do-ecdh */
+
+ unsigned prf_id = T0_POP();
+ unsigned ecdhe = T0_POP();
+ int x;
+
+ x = make_pms_ecdh(CTX, ecdhe, prf_id);
+ if (x < 0) {
+ br_ssl_engine_fail(ENG, -x);
+ T0_CO();
+ } else {
+ T0_PUSH(x);
+ }
+
+ }
+ break;
+ case 25: {
+ /* do-rsa-encrypt */
+
+ int x;
+
+ x = make_pms_rsa(CTX, T0_POP());
+ if (x < 0) {
+ br_ssl_engine_fail(ENG, -x);
+ T0_CO();
+ } else {
+ T0_PUSH(x);
+ }
+
+ }
+ break;
+ case 26: {
+ /* drop */
+ (void)T0_POP();
+ }
+ break;
+ case 27: {
+ /* dup */
+ T0_PUSH(T0_PEEK(0));
+ }
+ break;
+ case 28: {
+ /* fail */
+
+ br_ssl_engine_fail(ENG, (int)T0_POPi());
+ T0_CO();
+
+ }
+ break;
+ case 29: {
+ /* flush-record */
+
+ br_ssl_engine_flush_record(ENG);
+
+ }
+ break;
+ case 30: {
+ /* get16 */
+
+ size_t addr = (size_t)T0_POP();
+ T0_PUSH(*(uint16_t *)((unsigned char *)ENG + addr));
+
+ }
+ break;
+ case 31: {
+ /* get8 */
+
+ size_t addr = (size_t)T0_POP();
+ T0_PUSH(*((unsigned char *)ENG + addr));
+
+ }
+ break;
+ case 32: {
+ /* has-input? */
+
+ T0_PUSHi(-(ENG->hlen_in != 0));
+
+ }
+ break;
+ case 33: {
+ /* memcmp */
+
+ size_t len = (size_t)T0_POP();
+ void *addr2 = (unsigned char *)ENG + (size_t)T0_POP();
+ void *addr1 = (unsigned char *)ENG + (size_t)T0_POP();
+ int x = memcmp(addr1, addr2, len);
+ T0_PUSH((uint32_t)-(x == 0));
+
+ }
+ break;
+ case 34: {
+ /* memcpy */
+
+ size_t len = (size_t)T0_POP();
+ void *src = (unsigned char *)ENG + (size_t)T0_POP();
+ void *dst = (unsigned char *)ENG + (size_t)T0_POP();
+ memcpy(dst, src, len);
+
+ }
+ break;
+ case 35: {
+ /* mkrand */
+
+ size_t len = (size_t)T0_POP();
+ void *addr = (unsigned char *)ENG + (size_t)T0_POP();
+ br_hmac_drbg_generate(&ENG->rng, addr, len);
+
+ }
+ break;
+ case 36: {
+ /* more-incoming-bytes? */
+
+ T0_PUSHi(ENG->hlen_in != 0 || !br_ssl_engine_recvrec_finished(ENG));
+
+ }
+ break;
+ case 37: {
+ /* multihash-init */
+
+ br_multihash_init(&ENG->mhash);
+
+ }
+ break;
+ case 38: {
+ /* not */
+
+ uint32_t a = T0_POP();
+ T0_PUSH(~a);
+
+ }
+ break;
+ case 39: {
+ /* or */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a | b);
+
+ }
+ break;
+ case 40: {
+ /* over */
+ T0_PUSH(T0_PEEK(1));
+ }
+ break;
+ case 41: {
+ /* read-chunk-native */
+
+ size_t clen = ENG->hlen_in;
+ if (clen > 0) {
+ uint32_t addr, len;
+
+ len = T0_POP();
+ addr = T0_POP();
+ if ((size_t)len < clen) {
+ clen = (size_t)len;
+ }
+ memcpy((unsigned char *)ENG + addr, ENG->hbuf_in, clen);
+ if (ENG->record_type_in == BR_SSL_HANDSHAKE) {
+ br_multihash_update(&ENG->mhash, ENG->hbuf_in, clen);
+ }
+ T0_PUSH(addr + (uint32_t)clen);
+ T0_PUSH(len - (uint32_t)clen);
+ ENG->hbuf_in += clen;
+ ENG->hlen_in -= clen;
+ }
+
+ }
+ break;
+ case 42: {
+ /* read8-native */
+
+ if (ENG->hlen_in > 0) {
+ unsigned char x;
+
+ x = *ENG->hbuf_in ++;
+ if (ENG->record_type_in == BR_SSL_HANDSHAKE) {
+ br_multihash_update(&ENG->mhash, &x, 1);
+ }
+ T0_PUSH(x);
+ ENG->hlen_in --;
+ } else {
+ T0_PUSHi(-1);
+ }
+
+ }
+ break;
+ case 43: {
+ /* set16 */
+
+ size_t addr = (size_t)T0_POP();
+ *(uint16_t *)((unsigned char *)ENG + addr) = (uint16_t)T0_POP();
+
+ }
+ break;
+ case 44: {
+ /* set8 */
+
+ size_t addr = (size_t)T0_POP();
+ *((unsigned char *)ENG + addr) = (unsigned char)T0_POP();
+
+ }
+ break;
+ case 45: {
+ /* strlen */
+
+ void *str = (unsigned char *)ENG + (size_t)T0_POP();
+ T0_PUSH((uint32_t)strlen(str));
+
+ }
+ break;
+ case 46: {
+ /* supported-curves */
+
+ uint32_t x = ENG->iec == NULL ? 0 : ENG->iec->supported_curves;
+ T0_PUSH(x);
+
+ }
+ break;
+ case 47: {
+ /* supported-hash-functions */
+
+ int i;
+ unsigned x, num;
+
+ x = 0;
+ num = 0;
+ for (i = br_sha1_ID; i <= br_sha512_ID; i ++) {
+ if (br_multihash_getimpl(&ENG->mhash, i)) {
+ x |= 1U << i;
+ num ++;
+ }
+ }
+ T0_PUSH(x);
+ T0_PUSH(num);
+
+ }
+ break;
+ case 48: {
+ /* supports-ecdsa? */
+
+ T0_PUSHi(-(CTX->iecdsa != 0));
+
+ }
+ break;
+ case 49: {
+ /* supports-rsa-sign? */
+
+ T0_PUSHi(-(CTX->irsavrfy != 0));
+
+ }
+ break;
+ case 50: {
+ /* swap */
+ T0_SWAP();
+ }
+ break;
+ case 51: {
+ /* switch-aesgcm-in */
+
+ int is_client, prf_id;
+ unsigned cipher_key_len;
+
+ cipher_key_len = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_gcm_in(ENG, is_client, prf_id,
+ ENG->iaes_ctr, cipher_key_len);
+
+ }
+ break;
+ case 52: {
+ /* switch-aesgcm-out */
+
+ int is_client, prf_id;
+ unsigned cipher_key_len;
+
+ cipher_key_len = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_gcm_out(ENG, is_client, prf_id,
+ ENG->iaes_ctr, cipher_key_len);
+
+ }
+ break;
+ case 53: {
+ /* switch-cbc-in */
+
+ int is_client, prf_id, mac_id, aes;
+ unsigned cipher_key_len;
+
+ cipher_key_len = T0_POP();
+ aes = T0_POP();
+ mac_id = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_cbc_in(ENG, is_client, prf_id, mac_id,
+ aes ? ENG->iaes_cbcdec : ENG->ides_cbcdec, cipher_key_len);
+
+ }
+ break;
+ case 54: {
+ /* switch-cbc-out */
+
+ int is_client, prf_id, mac_id, aes;
+ unsigned cipher_key_len;
+
+ cipher_key_len = T0_POP();
+ aes = T0_POP();
+ mac_id = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_cbc_out(ENG, is_client, prf_id, mac_id,
+ aes ? ENG->iaes_cbcenc : ENG->ides_cbcenc, cipher_key_len);
+
+ }
+ break;
+ case 55: {
+ /* u>> */
+
+ int c = (int)T0_POPi();
+ uint32_t x = T0_POP();
+ T0_PUSH(x >> c);
+
+ }
+ break;
+ case 56: {
+ /* verify-SKE-sig */
+
+ size_t sig_len = T0_POP();
+ int use_rsa = T0_POPi();
+ int hash = T0_POPi();
+
+ T0_PUSH(verify_SKE_sig(CTX, hash, use_rsa, sig_len));
+
+ }
+ break;
+ case 57: {
+ /* write-blob-chunk */
+
+ size_t clen = ENG->hlen_out;
+ if (clen > 0) {
+ uint32_t addr, len;
+
+ len = T0_POP();
+ addr = T0_POP();
+ if ((size_t)len < clen) {
+ clen = (size_t)len;
+ }
+ memcpy(ENG->hbuf_out, (unsigned char *)ENG + addr, clen);
+ if (ENG->record_type_out == BR_SSL_HANDSHAKE) {
+ br_multihash_update(&ENG->mhash, ENG->hbuf_out, clen);
+ }
+ T0_PUSH(addr + (uint32_t)clen);
+ T0_PUSH(len - (uint32_t)clen);
+ ENG->hbuf_out += clen;
+ ENG->hlen_out -= clen;
+ }
+
+ }
+ break;
+ case 58: {
+ /* write8-native */
+
+ unsigned char x;
+
+ x = (unsigned char)T0_POP();
+ if (ENG->hlen_out > 0) {
+ if (ENG->record_type_out == BR_SSL_HANDSHAKE) {
+ br_multihash_update(&ENG->mhash, &x, 1);
+ }
+ *ENG->hbuf_out ++ = x;
+ ENG->hlen_out --;
+ T0_PUSHi(-1);
+ } else {
+ T0_PUSHi(0);
+ }
+
+ }
+ break;
+ case 59: {
+ /* x509-append */
+
+ const br_x509_class *xc;
+ size_t len;
+
+ xc = *(ENG->x509ctx);
+ len = T0_POP();
+ xc->append(ENG->x509ctx, ENG->pad, len);
+
+ }
+ break;
+ case 60: {
+ /* x509-end-cert */
+
+ const br_x509_class *xc;
+
+ xc = *(ENG->x509ctx);
+ xc->end_cert(ENG->x509ctx);
+
+ }
+ break;
+ case 61: {
+ /* x509-end-chain */
+
+ const br_x509_class *xc;
+
+ xc = *(ENG->x509ctx);
+ T0_PUSH(xc->end_chain(ENG->x509ctx));
+
+ }
+ break;
+ case 62: {
+ /* x509-start-cert */
+
+ const br_x509_class *xc;
+
+ xc = *(ENG->x509ctx);
+ xc->start_cert(ENG->x509ctx, T0_POP());
+
+ }
+ break;
+ case 63: {
+ /* x509-start-chain */
+
+ const br_x509_class *xc;
+
+ xc = *(ENG->x509ctx);
+ xc->start_chain(ENG->x509ctx, T0_POP(), ENG->server_name);
+
+ }
+ break;
+ }
+
+ } else {
+ T0_ENTER(ip, rp, t0x);
+ }
+ }
+t0_exit:
+ ((t0_context *)t0ctx)->dp = dp;
+ ((t0_context *)t0ctx)->rp = rp;
+ ((t0_context *)t0ctx)->ip = ip;
+}
--- /dev/null
+\ 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.
+
+\ ----------------------------------------------------------------------
+\ Handshake processing code, for the client.
+\ The common T0 code (ssl_hs_common.t0) shall be read first.
+
+preamble {
+
+/*
+ * This macro evaluates to a pointer to the client context, under that
+ * specific name. It must be noted that since the engine context is the
+ * first field of the br_ssl_client_context structure ('eng'), then
+ * pointers values of both types are interchangeable, modulo an
+ * appropriate cast. This also means that "adresses" computed as offsets
+ * within the structure work for both kinds of context.
+ */
+#define CTX ((br_ssl_client_context *)ENG)
+
+/*
+ * Generate the pre-master secret for RSA key exchange, and encrypt it
+ * with the server's public key. Returned value is either the encrypted
+ * data length (in bytes), or -x on error, with 'x' being an error code.
+ *
+ * This code assumes that the public key has been already verified (it
+ * was properly obtained by the X.509 engine, and it has the right type,
+ * i.e. it is of type RSA and suitable for encryption).
+ */
+static int
+make_pms_rsa(br_ssl_client_context *ctx, int prf_id)
+{
+ const br_x509_class **xc;
+ const br_x509_pkey *pk;
+ const unsigned char *n;
+ unsigned char *pms;
+ size_t nlen, u;
+
+ xc = ctx->eng.x509ctx;
+ pk = (*xc)->get_pkey(xc);
+
+ /*
+ * Compute actual RSA key length, in case there are leading zeros.
+ */
+ n = pk->key.rsa.n;
+ nlen = pk->key.rsa.nlen;
+ while (nlen > 0 && *n == 0) {
+ n ++;
+ nlen --;
+ }
+
+ /*
+ * We need at least 59 bytes (48 bytes for pre-master secret, and
+ * 11 bytes for the PKCS#1 type 2 padding). Note that the X.509
+ * minimal engine normally blocks RSA keys shorter than 128 bytes,
+ * so this is mostly for public keys provided explicitly by the
+ * caller.
+ */
+ if (nlen < 59) {
+ return -BR_ERR_X509_WEAK_PUBLIC_KEY;
+ }
+ if (nlen > sizeof ctx->eng.pad) {
+ return -BR_ERR_LIMIT_EXCEEDED;
+ }
+
+ /*
+ * Make PMS.
+ */
+ pms = ctx->eng.pad + nlen - 48;
+ br_enc16be(pms, ctx->eng.version_max);
+ br_hmac_drbg_generate(&ctx->eng.rng, pms + 2, 46);
+ br_ssl_engine_compute_master(&ctx->eng, prf_id, pms, 48);
+
+ /*
+ * Apply PKCS#1 type 2 padding.
+ */
+ ctx->eng.pad[0] = 0x00;
+ ctx->eng.pad[1] = 0x02;
+ ctx->eng.pad[nlen - 49] = 0x00;
+ br_hmac_drbg_generate(&ctx->eng.rng, ctx->eng.pad + 2, nlen - 51);
+ for (u = 2; u < nlen - 49; u ++) {
+ while (ctx->eng.pad[u] == 0) {
+ br_hmac_drbg_generate(&ctx->eng.rng,
+ &ctx->eng.pad[u], 1);
+ }
+ }
+
+ /*
+ * Compute RSA encryption.
+ */
+ if (!ctx->irsapub(ctx->eng.pad, nlen, &pk->key.rsa)) {
+ return -BR_ERR_LIMIT_EXCEEDED;
+ }
+ return (int)nlen;
+}
+
+/*
+ * OID for hash functions in RSA signatures.
+ */
+static const unsigned char HASH_OID_SHA1[] = {
+ 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A
+};
+
+static const unsigned char HASH_OID_SHA224[] = {
+ 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04
+};
+
+static const unsigned char HASH_OID_SHA256[] = {
+ 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01
+};
+
+static const unsigned char HASH_OID_SHA384[] = {
+ 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02
+};
+
+static const unsigned char HASH_OID_SHA512[] = {
+ 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03
+};
+
+static const unsigned char *HASH_OID[] = {
+ HASH_OID_SHA1,
+ HASH_OID_SHA224,
+ HASH_OID_SHA256,
+ HASH_OID_SHA384,
+ HASH_OID_SHA512
+};
+
+/*
+ * Check the RSA signature on the ServerKeyExchange message.
+ * hash hash function ID (2 to 6), or 0 for MD5+SHA-1 (with RSA only)
+ * use_rsa non-zero for RSA signature, zero for ECDSA
+ * sig_len signature length (in bytes); signature value is in the pad
+ * Returned value is 0 on success, or an error code.
+ */
+static int
+verify_SKE_sig(br_ssl_client_context *ctx,
+ int hash, int use_rsa, size_t sig_len)
+{
+ const br_x509_class **xc;
+ const br_x509_pkey *pk;
+ br_multihash_context mhc;
+ unsigned char hv[64], head[4];
+ size_t hv_len;
+
+ xc = ctx->eng.x509ctx;
+ pk = (*xc)->get_pkey(xc);
+ br_multihash_zero(&mhc);
+ br_multihash_copyimpl(&mhc, &ctx->eng.mhash);
+ br_multihash_init(&mhc);
+ br_multihash_update(&mhc,
+ ctx->eng.client_random, sizeof ctx->eng.client_random);
+ br_multihash_update(&mhc,
+ ctx->eng.server_random, sizeof ctx->eng.server_random);
+ head[0] = 3;
+ head[1] = 0;
+ head[2] = ctx->eng.ecdhe_curve;
+ head[3] = ctx->eng.ecdhe_point_len;
+ br_multihash_update(&mhc, head, sizeof head);
+ br_multihash_update(&mhc,
+ ctx->eng.ecdhe_point, ctx->eng.ecdhe_point_len);
+ if (hash) {
+ hv_len = br_multihash_out(&mhc, hash, hv);
+ if (hv_len == 0) {
+ return BR_ERR_INVALID_ALGORITHM;
+ }
+ } else {
+ if (!br_multihash_out(&mhc, br_md5_ID, hv)
+ || !br_multihash_out(&mhc, br_sha1_ID, hv + 16))
+ {
+ return BR_ERR_INVALID_ALGORITHM;
+ }
+ hv_len = 36;
+ }
+ if (use_rsa) {
+ unsigned char tmp[64];
+ const unsigned char *hash_oid;
+
+ if (hash) {
+ hash_oid = HASH_OID[hash - 2];
+ } else {
+ hash_oid = NULL;
+ }
+ if (!ctx->irsavrfy(ctx->eng.pad, sig_len,
+ hash_oid, hv_len, &pk->key.rsa, tmp)
+ || memcmp(tmp, hv, hv_len) != 0)
+ {
+ return BR_ERR_BAD_SIGNATURE;
+ }
+ } else {
+ if (!ctx->iecdsa(ctx->eng.iec, hv, hv_len, &pk->key.ec,
+ ctx->eng.pad, sig_len))
+ {
+ return BR_ERR_BAD_SIGNATURE;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Perform client-size ECDH (or ECDHE). The point that should be sent to
+ * the server is written in the pad; returned value is either the point
+ * length (in bytes), or -x on error, with 'x' being an error code.
+ *
+ * The point _from_ the server is taken from ecdhe_point[] if 'ecdhe'
+ * is non-zero, or from the X.509 engine context if 'ecdhe' is zero
+ * (for static ECDH).
+ */
+static int
+make_pms_ecdh(br_ssl_client_context *ctx, unsigned ecdhe, int prf_id)
+{
+ int curve;
+ unsigned char key[66], point[133];
+ const unsigned char *generator, *order, *point_src;
+ size_t glen, olen, point_len;
+ unsigned char mask;
+
+ if (ecdhe) {
+ curve = ctx->eng.ecdhe_curve;
+ point_src = ctx->eng.ecdhe_point;
+ point_len = ctx->eng.ecdhe_point_len;
+ } else {
+ const br_x509_class **xc;
+ const br_x509_pkey *pk;
+
+ xc = ctx->eng.x509ctx;
+ pk = (*xc)->get_pkey(xc);
+ curve = pk->key.ec.curve;
+ point_src = pk->key.ec.q;
+ point_len = pk->key.ec.qlen;
+ }
+ if ((ctx->eng.iec->supported_curves & ((uint32_t)1 << curve)) == 0) {
+ return -BR_ERR_INVALID_ALGORITHM;
+ }
+
+ /*
+ * We need to generate our key, as a non-zero random value which
+ * is lower than the curve order, in a "large enough" range. We
+ * force top bit to 0 and bottom bit to 1, which guarantees that
+ * the value is in the proper range.
+ */
+ order = ctx->eng.iec->order(curve, &olen);
+ mask = 0xFF;
+ while (mask >= order[0]) {
+ mask >>= 1;
+ }
+ br_hmac_drbg_generate(&ctx->eng.rng, key, olen);
+ key[0] &= mask;
+ key[olen - 1] |= 0x01;
+
+ /*
+ * Compute the common ECDH point, whose X coordinate is the
+ * pre-master secret.
+ */
+ generator = ctx->eng.iec->generator(curve, &glen);
+ if (glen != point_len) {
+ return -BR_ERR_INVALID_ALGORITHM;
+ }
+
+ memcpy(point, point_src, glen);
+ if (!ctx->eng.iec->mul(point, glen, key, olen, curve)) {
+ return -BR_ERR_INVALID_ALGORITHM;
+ }
+
+ /*
+ * The pre-master secret is the X coordinate.
+ */
+ br_ssl_engine_compute_master(&ctx->eng, prf_id, point + 1, glen >> 1);
+
+ memcpy(point, generator, glen);
+ if (!ctx->eng.iec->mul(point, glen, key, olen, curve)) {
+ return -BR_ERR_INVALID_ALGORITHM;
+ }
+ memcpy(ctx->eng.pad, point, glen);
+ return (int)glen;
+}
+
+}
+
+\ =======================================================================
+
+: addr-ctx:
+ next-word { field }
+ "addr-" field + 0 1 define-word
+ 0 8191 "offsetof(br_ssl_client_context, " field + ")" + make-CX
+ postpone literal postpone ; ;
+
+\ Length of the Secure Renegotiation extension. This is 5 for the
+\ first handshake, 17 for a renegotiation (if the server supports the
+\ extension), or 0 if we know that the server does not support the
+\ extension.
+: ext-reneg-length ( -- n )
+ addr-reneg get8 dup if 1 - 17 * else drop 5 then ;
+
+\ Length of SNI extension.
+: ext-sni-length ( -- len )
+ addr-server_name strlen dup if 9 + then ;
+
+\ Length of Maximum Fragment Length extension.
+: ext-frag-length ( -- len )
+ addr-log_max_frag_len get8 14 = if 0 else 5 then ;
+
+\ Test support for RSA signatures.
+cc: supports-rsa-sign? ( -- bool ) {
+ T0_PUSHi(-(CTX->irsavrfy != 0));
+}
+
+\ Test support for ECDSA signatures.
+cc: supports-ecdsa? ( -- bool ) {
+ T0_PUSHi(-(CTX->iecdsa != 0));
+}
+
+\ Length of Signatures extension.
+: ext-signatures-length ( -- len )
+ supported-hash-functions { x } drop
+ 0
+ supports-rsa-sign? if x + then
+ supports-ecdsa? if x + then
+ dup if 1 << 6 + then ;
+
+\ Write supported hash functions ( sign -- )
+: write-hashes
+ { sign }
+ supported-hash-functions drop
+ \ We advertise hash functions in the following preference order:
+ \ SHA-256 SHA-224 SHA-384 SHA-512 SHA-1
+ \ Rationale:
+ \ -- SHA-256 and SHA-224 are more efficient on 32-bit architectures
+ \ -- SHA-1 is less than ideally collision-resistant
+ dup 0x10 and if 4 write8 sign write8 then
+ dup 0x08 and if 3 write8 sign write8 then
+ dup 0x20 and if 5 write8 sign write8 then
+ dup 0x40 and if 6 write8 sign write8 then
+ 0x04 and if 2 write8 sign write8 then ;
+
+\ Length of Supported Curves extension.
+: ext-supported-curves-length ( -- len )
+ supported-curves dup if
+ 0 { x }
+ begin dup while
+ dup 1 and x + >x
+ 1 >>
+ repeat
+ drop x 1 << 6 +
+ then ;
+
+\ Length of Supported Point Formats extension.
+: ext-point-format-length ( -- len )
+ supported-curves if 6 else 0 then ;
+
+\ Write handshake message: ClientHello
+: write-ClientHello ( -- )
+ { ; total-ext-length }
+
+ \ Compute length for extensions (without the general two-byte header)
+ ext-reneg-length ext-sni-length + ext-frag-length +
+ ext-signatures-length +
+ ext-supported-curves-length + ext-point-format-length +
+ >total-ext-length
+
+ \ ClientHello type
+ 1 write8
+
+ \ Compute and write length
+ 39 addr-session_id_len get8 + addr-suites_num get8 1 << +
+ total-ext-length if 2+ total-ext-length + then
+ write24
+
+ \ Protocol version
+ addr-version_max get16 write16
+
+ \ Client random
+ addr-client_random 4 bzero
+ addr-client_random 4 + 28 mkrand
+ addr-client_random 32 write-blob
+
+ \ Session ID
+ addr-session_id addr-session_id_len get8 write-blob-head8
+
+ \ Supported cipher suites. We also check here that we indeed
+ \ support all these suites.
+ addr-suites_num get8 dup 1 << write16
+ addr-suites_buf swap
+ begin
+ dup while 1-
+ over get16
+ dup suite-supported? ifnot ERR_BAD_CIPHER_SUITE fail then
+ write16
+ swap 2+ swap
+ repeat
+ 2drop
+
+ \ Compression methods (only "null" compression)
+ 1 write8 0 write8
+
+ \ Extensions
+ total-ext-length if
+ total-ext-length write16
+ ext-reneg-length if
+ 0xFF01 write16 \ extension type (0xFF01)
+ addr-saved_finished
+ ext-reneg-length 4 - dup write16 \ extension length
+ 1- write-blob-head8 \ verify data
+ then
+ ext-sni-length if
+ 0x0000 write16 \ extension type (0)
+ addr-server_name
+ ext-sni-length 4 - dup write16 \ extension length
+ 2 - dup write16 \ ServerNameList length
+ 0 write8 \ name type: host_name
+ 3 - write-blob-head16 \ the name itself
+ then
+ ext-frag-length if
+ 0x0001 write16 \ extension type (1)
+ 0x0001 write16 \ extension length
+ addr-log_max_frag_len get8 8 - write8
+ then
+ ext-signatures-length if
+ 0x000D write16 \ extension type (13)
+ ext-signatures-length 4 - dup write16 \ extension length
+ 2 - write16 \ list length
+ supports-ecdsa? if 3 write-hashes then
+ supports-rsa-sign? if 1 write-hashes then
+ then
+ \ TODO: add an API to specify preference order for curves.
+ \ Right now we use increasing id order, which makes P-256
+ \ the preferred curve.
+ ext-supported-curves-length dup if
+ 0x000A write16 \ extension type (10)
+ 4 - dup write16 \ extension length
+ 2- write16 \ list length
+ supported-curves 0
+ begin dup 32 < while
+ dup2 >> 1 and if dup write16 then
+ 1+
+ repeat
+ 2drop
+ else
+ drop
+ then
+ ext-point-format-length if
+ 0x000B write16 \ extension type (11)
+ 0x0002 write16 \ extension length
+ 0x0100 write16 \ value: 1 format: uncompressed
+ then
+ then
+ ;
+
+\ =======================================================================
+
+\ Parse server SNI extension. If present, then it should be empty.
+: read-server-sni ( lim -- lim )
+ read16 if ERR_BAD_SNI fail then ;
+
+\ Parse server Max Fragment Length extension. If present, then it should
+\ advertise the same length as the client. Note that whether the server
+\ sends it or not changes nothing for us: we won't send any record larger
+\ than the advertised value anyway, and we will accept incoming records
+\ up to our input buffer length.
+: read-server-frag ( lim -- lim )
+ read16 1 = ifnot ERR_BAD_FRAGLEN fail then
+ read8 8 + addr-log_max_frag_len get8 = ifnot ERR_BAD_FRAGLEN fail then ;
+
+\ Parse server Secure Renegotiation extension. This is called only if
+\ the client sent that extension, so we only have two cases to
+\ distinguish: first handshake, and renegotiation; in the latter case,
+\ we know that the server supports the extension, otherwise the client
+\ would not have sent it.
+: read-server-reneg ( lim -- lim )
+ read16
+ addr-reneg get8 ifnot
+ \ "reneg" is 0, so this is a first handshake. The server's
+ \ extension MUST be empty. We also learn that the server
+ \ supports the extension.
+ 1 = ifnot ERR_BAD_SECRENEG fail then
+ read8 0 = ifnot ERR_BAD_SECRENEG fail then
+ 2 addr-reneg set8
+ else
+ \ "reneg" is non-zero, and we sent an extension, so it must
+ \ be 2 and this is a renegotiation. We must verify that
+ \ the extension contents have length exactly 24 bytes and
+ \ match the saved client and server "Finished".
+ 25 = ifnot ERR_BAD_SECRENEG fail then
+ read8 24 = ifnot ERR_BAD_SECRENEG fail then
+ addr-pad 24 read-blob
+ addr-saved_finished addr-pad 24 memcmp ifnot
+ ERR_BAD_SECRENEG fail
+ then
+ then ;
+
+\ Save a value in a 16-bit field, or check it in case of session resumption.
+: check-resume ( val addr resume -- )
+ if get16 = ifnot ERR_RESUME_MISMATCH fail then else set16 then ;
+
+cc: DEBUG-BLOB ( addr len -- ) {
+ extern int printf(const char *fmt, ...);
+
+ size_t len = T0_POP();
+ unsigned char *buf = (unsigned char *)CTX + T0_POP();
+ size_t u;
+
+ printf("BLOB:");
+ for (u = 0; u < len; u ++) {
+ if (u % 16 == 0) {
+ printf("\n ");
+ }
+ printf(" %02x", buf[u]);
+ }
+ printf("\n");
+}
+
+\ Parse incoming ServerHello. Returned value is true (-1) on session
+\ resumption.
+: read-ServerHello ( -- bool )
+ \ Get header, and check message type.
+ read-handshake-header 2 = ifnot ERR_UNEXPECTED fail then
+
+ \ Get protocol version.
+ read16 { version }
+ version addr-version_min get16 < version addr-version_max get16 > or if
+ ERR_UNSUPPORTED_VERSION fail
+ then
+
+ \ Enforce chosen version for subsequent records in both directions.
+ version addr-version_in get16 <> if ERR_BAD_VERSION fail then
+ version addr-version_out set16
+
+ \ Server random.
+ addr-server_random 32 read-blob
+
+ \ The "session resumption" flag.
+ 0 { resume }
+
+ \ Session ID.
+ read8 { idlen }
+ idlen 32 > if ERR_OVERSIZED_ID fail then
+ addr-pad idlen read-blob
+ idlen addr-session_id_len get8 = idlen 0 > and if
+ addr-session_id addr-pad idlen memcmp if
+ \ Server session ID is non-empty and matches what
+ \ we sent, so this is a session resumption.
+ -1 >resume
+ then
+ then
+ addr-session_id addr-pad idlen memcpy
+ idlen addr-session_id_len set8
+
+ \ Record version.
+ version addr-version resume check-resume
+
+ \ Cipher suite. We check that it is part of the list of cipher
+ \ suites that we advertised.
+ \ read16 { suite ; found }
+ \ 0 >found
+ \ addr-suites_buf dup addr-suites_num get8 1 << +
+ \ begin dup2 < while
+ \ 2 - dup get16
+ \ suite = found or >found
+ \ repeat
+ \ 2drop found ifnot ERR_BAD_CIPHER_SUITE fail then
+ read16
+ dup scan-suite 0< if ERR_BAD_CIPHER_SUITE fail then
+ addr-cipher_suite resume check-resume
+
+ \ Compression method. Should be 0 (no compression).
+ read8 if ERR_BAD_COMPRESSION fail then
+
+ \ Parse extensions (if any). If there is no extension, then the
+ \ read limit (on the TOS) should be 0 at that point.
+ dup if
+ \ Length of extension list.
+ \ message size.
+ read16 open-elt
+
+ \ Enumerate extensions. For each of them, check that we
+ \ sent an extension of that type, and did not see it
+ \ yet; and then process it.
+ ext-sni-length { ok-sni }
+ ext-reneg-length { ok-reneg }
+ ext-frag-length { ok-frag }
+ ext-signatures-length { ok-signatures }
+ ext-supported-curves-length { ok-curves }
+ ext-point-format-length { ok-points }
+ begin dup while
+ read16
+ case
+ \ Server Name Indication. The server may
+ \ send such an extension if it uses the SNI
+ \ from the client, but that "response
+ \ extension" is supposed to be empty.
+ 0x0000 of
+ ok-sni ifnot
+ ERR_EXTRA_EXTENSION fail
+ then
+ 0 >ok-sni
+ read-server-sni
+ endof
+
+ \ Max Frag Length. The contents shall be
+ \ a single byte whose value matches the one
+ \ sent by the client.
+ 0x0001 of
+ ok-frag ifnot
+ ERR_EXTRA_EXTENSION fail
+ then
+ 0 >ok-frag
+ read-server-frag
+ endof
+
+ \ Secure Renegotiation.
+ 0xFF01 of
+ ok-reneg ifnot
+ ERR_EXTRA_EXTENSION fail
+ then
+ 0 >ok-reneg
+ read-server-reneg
+ endof
+
+ \ Signature Algorithms.
+ \ Normally, the server should never send this
+ \ extension (so says RFC 5246 #7.4.1.4.1),
+ \ but some existing servers do.
+ 0x000D of
+ ok-signatures ifnot
+ ERR_EXTRA_EXTENSION fail
+ then
+ 0 >ok-signatures
+ read-ignore-16
+ endof
+
+ \ Supported Curves.
+ 0x000A of
+ ok-curves ifnot
+ ERR_EXTRA_EXTENSION fail
+ then
+ 0 >ok-curves
+ read-ignore-16
+ endof
+
+ \ Supported Point Formats.
+ 0x000B of
+ ok-points ifnot
+ ERR_EXTRA_EXTENSION fail
+ then
+ 0 >ok-points
+ read-ignore-16
+ endof
+
+ ERR_EXTRA_EXTENSION fail
+ endcase
+ repeat
+
+ \ If we sent a secure renegotiation extension but did not
+ \ receive a response, then the server does not support
+ \ secure renegotiation. This is a hard failure if this
+ \ is a renegotiation.
+ ok-reneg if
+ ok-reneg 5 > if ERR_BAD_SECRENEG fail then
+ 1 addr-reneg set8
+ then
+ close-elt
+ then
+ close-elt
+ resume
+ ;
+
+cc: x509-start-chain ( expected-key-type -- ) {
+ const br_x509_class *xc;
+
+ xc = *(ENG->x509ctx);
+ xc->start_chain(ENG->x509ctx, T0_POP(), ENG->server_name);
+}
+
+cc: x509-start-cert ( length -- ) {
+ const br_x509_class *xc;
+
+ xc = *(ENG->x509ctx);
+ xc->start_cert(ENG->x509ctx, T0_POP());
+}
+
+cc: x509-append ( length -- ) {
+ const br_x509_class *xc;
+ size_t len;
+
+ xc = *(ENG->x509ctx);
+ len = T0_POP();
+ xc->append(ENG->x509ctx, ENG->pad, len);
+}
+
+cc: x509-end-cert ( -- ) {
+ const br_x509_class *xc;
+
+ xc = *(ENG->x509ctx);
+ xc->end_cert(ENG->x509ctx);
+}
+
+cc: x509-end-chain ( -- err ) {
+ const br_x509_class *xc;
+
+ xc = *(ENG->x509ctx);
+ T0_PUSH(xc->end_chain(ENG->x509ctx));
+}
+
+\ Parse Certificate
+: read-Certificate ( -- )
+ \ Get header, and check message type.
+ read-handshake-header 11 = ifnot ERR_UNEXPECTED fail then
+
+ \ Start processing the chain through the X.509 engine.
+ addr-cipher_suite get16 expected-key-type
+ x509-start-chain
+
+ \ Total chain length is a 24-bit integer.
+ read24 open-elt
+ begin
+ dup while
+ read24 open-elt
+ dup x509-start-cert
+
+ \ We read the certificate by chunks through the pad, so
+ \ as to use the existing reading function (read-blob)
+ \ that also ensures proper hashing.
+ begin
+ dup while
+ dup 256 > if 256 else dup then { len }
+ addr-pad len read-blob
+ len x509-append
+ repeat
+ close-elt
+ x509-end-cert
+ repeat
+
+ \ We must close the chain AND the handshake message.
+ close-elt
+ close-elt
+
+ \ Chain processing is finished; get the error code.
+ x509-end-chain
+ dup if fail then drop
+ ;
+
+\ Verify signature on ECDHE point sent by the server.
+\ 'hash' is the hash function to use (1 to 6, or 0 for RSA with MD5+SHA-1)
+\ 'use-rsa' is 0 for ECDSA, -1 for for RSA
+\ 'sig-len' is the signature length (in bytes)
+\ The signature itself is in the pad.
+cc: verify-SKE-sig ( hash use-rsa sig-len -- err ) {
+ size_t sig_len = T0_POP();
+ int use_rsa = T0_POPi();
+ int hash = T0_POPi();
+
+ T0_PUSH(verify_SKE_sig(CTX, hash, use_rsa, sig_len));
+}
+
+\ Parse ServerKeyExchange
+: read-ServerKeyExchange ( -- )
+ \ Get header, and check message type.
+ read-handshake-header 12 = ifnot ERR_UNEXPECTED fail then
+
+ \ We expect a named curve, and we must support it.
+ read8 3 = ifnot ERR_INVALID_ALGORITHM fail then
+ read16 dup addr-ecdhe_curve set8
+ dup 32 >= if ERR_INVALID_ALGORITHM fail then
+ supported-curves swap >> 1 and ifnot ERR_INVALID_ALGORITHM fail then
+
+ \ Read the server point.
+ read8
+ dup 133 > if ERR_INVALID_ALGORITHM fail then
+ dup addr-ecdhe_point_len set8
+ addr-ecdhe_point swap read-blob
+
+ \ If using TLS-1.2+, then the hash function and signature algorithm
+ \ are explicitly provided; the signature algorithm must match what
+ \ the cipher suite specifies. With TLS-1.0 and 1.1, the signature
+ \ algorithm is inferred from the cipher suite, and the hash is
+ \ either MD5+SHA-1 (for RSA signatures) or SHA-1 (for ECDSA).
+ addr-version get16 0x0303 >= { tls1.2+ }
+ addr-cipher_suite get16 use-rsa-ecdhe? { use-rsa }
+ 2 { hash }
+ tls1.2+ if
+ \ Read hash function; accept only the SHA-* identifiers
+ \ (from SHA-1 to SHA-512, no MD5 here).
+ read8
+ dup dup 2 < swap 6 > or if ERR_INVALID_ALGORITHM fail then
+ >hash
+ read8
+ \ Get expected signature algorithm and compare with what
+ \ the server just sent. Expected value is 1 for RSA, 3
+ \ for ECDSA. Note that 'use-rsa' evaluates to -1 for RSA,
+ \ 0 for ECDSA.
+ use-rsa 1 << 3 + = ifnot ERR_INVALID_ALGORITHM fail then
+ else
+ \ For MD5+SHA-1, we set 'hash' to 0.
+ use-rsa if 0 >hash then
+ then
+
+ \ Read signature into the pad.
+ read16 dup { sig-len }
+
+ dup 512 > if ERR_LIMIT_EXCEEDED fail then
+ addr-pad swap read-blob
+
+ \ Verify signature.
+ hash use-rsa sig-len verify-SKE-sig
+ dup if fail then drop
+
+ close-elt ;
+
+\ Parse CertificateRequest. Header has already been read.
+: read-contents-CertificateRequest ( lim -- )
+ \ TODO: implement client certificates. Right now, we simply
+ \ drop the complete message.
+ begin dup while read8 drop repeat drop ;
+
+\ Write an empty Certificate message.
+: write-empty-Certificate ( -- )
+ 11 write8 3 write24 0 write24 ;
+
+cc: do-rsa-encrypt ( prf_id -- nlen ) {
+ int x;
+
+ x = make_pms_rsa(CTX, T0_POP());
+ if (x < 0) {
+ br_ssl_engine_fail(ENG, -x);
+ T0_CO();
+ } else {
+ T0_PUSH(x);
+ }
+}
+
+cc: do-ecdh ( echde prf_id -- ulen ) {
+ unsigned prf_id = T0_POP();
+ unsigned ecdhe = T0_POP();
+ int x;
+
+ x = make_pms_ecdh(CTX, ecdhe, prf_id);
+ if (x < 0) {
+ br_ssl_engine_fail(ENG, -x);
+ T0_CO();
+ } else {
+ T0_PUSH(x);
+ }
+}
+
+\ Write ClientKeyExchange
+: write-ClientKeyExchange ( -- )
+ 16 write8
+ addr-cipher_suite get16
+ dup use-rsa-keyx? if
+ prf-id do-rsa-encrypt
+ dup 2+ write24
+ dup write16
+ addr-pad swap write-blob
+ else
+ dup use-ecdhe? swap prf-id do-ecdh
+ dup 1+ write24
+ dup write8
+ addr-pad swap write-blob
+ then ;
+
+\ =======================================================================
+
+\ Perform a handshake.
+: do-handshake ( -- )
+ 0 addr-application_data set8
+ 22 addr-record_type_out set8
+ multihash-init
+
+ write-ClientHello
+ flush-record
+ read-ServerHello
+
+ if
+ \ Session resumption.
+ -1 read-CCS-Finished
+ -1 write-CCS-Finished
+
+ else
+
+ \ Not a session resumption.
+
+ read-Certificate
+
+ \ Depending on cipher suite, we may now expect a
+ \ ServerKeyExchange.
+ addr-cipher_suite get16 expected-key-type
+ CX 0 63 { BR_KEYTYPE_SIGN } and if
+ read-ServerKeyExchange
+ then
+
+ \ Get next header.
+ read-handshake-header
+
+ \ If this is a CertificateRequest, parse it, then read
+ \ next header.
+ dup 13 = if
+ drop read-contents-CertificateRequest
+ read-handshake-header
+ -1
+ else
+ 0
+ then
+ { seen-CR }
+
+ \ At that point, we should have a ServerHelloDone,
+ \ whose length must be 0.
+ 14 = ifnot ERR_UNEXPECTED fail then
+ if ERR_BAD_HELLO_DONE fail then
+
+ \ There should not be more bytes in the record at that point.
+ more-incoming-bytes? if ERR_UNEXPECTED fail then
+
+ seen-CR if
+ \ TODO: client certificate support.
+ write-empty-Certificate
+ then
+ write-ClientKeyExchange
+
+ \ TODO: CertificateVerify
+
+ -1 write-CCS-Finished
+ -1 read-CCS-Finished
+ then
+
+ \ Now we should be invoked only in case of renegotiation.
+ 1 addr-application_data set8
+ 23 addr-record_type_out set8 ;
+
+\ Read a HelloRequest message.
+: read-HelloRequest ( -- )
+ \ A HelloRequest has length 0 and type 0.
+ read-handshake-header-core
+ if ERR_UNEXPECTED fail then
+ if ERR_BAD_HANDSHAKE fail then ;
+
+\ Entry point.
+: main ( -- ! )
+ \ Perform initial handshake.
+ do-handshake
+
+ begin
+ \ Wait for further invocation. At that point, we should
+ \ get either an explicit call for renegotiation, or
+ \ an incoming HelloRequest handshake message.
+ wait-co
+ dup 0x07 and case
+ 0x00 of
+ 0x10 and if
+ do-handshake
+ then
+ endof
+ 0x01 of
+ drop
+ 0 addr-application_data set8
+ read-HelloRequest
+ \ Reject renegotiations if the peer does not
+ \ support secure renegotiation. Theoretically
+ \ we could just ignore that, however if the
+ \ server sent an HelloRequest then it is
+ \ expecting a handshake and will wait for our
+ \ ClientHello.
+ addr-reneg get8 1 = if
+ flush-record
+ begin can-output? not while
+ wait-co drop
+ repeat
+ 100 send-warning
+ else
+ do-handshake
+ then
+ endof
+ ERR_UNEXPECTED fail
+ endcase
+ again
+ ;
--- /dev/null
+\ 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 is the common T0 code for processing handshake messages (code that
+\ is used by both client and server).
+
+preamble {
+
+#include <stddef.h>
+#include <string.h>
+
+#include "inner.h"
+
+/*
+ * This macro evaluates to a pointer to the current engine context.
+ */
+#define ENG ((br_ssl_engine_context *)((unsigned char *)t0ctx - offsetof(br_ssl_engine_context, cpu)))
+
+}
+
+\ IMPLEMENTATION NOTES
+\ ====================
+\
+\ This code handles all records except application data records.
+\ Application data is accepted (incoming records, outgoing payload data)
+\ only when the application_data flag is set, which is done at the end
+\ of the handshake; and it is cleared whenever a renegotiation or a
+\ closure takes place.
+\
+\ Incoming alerts are processed on the fly; fatal alerts terminate the
+\ context, while warnings are ignored, except for close_notify, which
+\ triggers the closure procedure. That procedure never returns (it ends
+\ with an 'ERR_OK fail' call). We can thus make this processing right
+\ into the read functions.
+\
+\ Specific actions from the caller (closure or renegotiation) may happen
+\ only when jumping back into the T0 code, i.e. just after a 'co' call.
+\ Similarly, incoming record type may change only while the caller has
+\ control, so we need to check that type only when returning from a 'co'.
+\
+\ The handshake processor needs to defer back to the caller ('co') only
+\ in one of the following situations:
+\
+\ -- Some handshake data is expected.
+\
+\ -- The handshake is finished, and application data may flow. There may
+\ be some incoming handshake data (HelloRequest from the server). This
+\ is the only situation where a renegotiation call won't be ignored.
+\
+\ -- Some change-cipher-spec data is expected.
+\
+\ -- An alert record is expected. Other types of incoming records will be
+\ skipped.
+\
+\ -- Waiting for the currently accumulated record to be sent and the
+\ output buffer to become free again for another record.
+
+\ Placeholder for handling not yet implemented functionalities.
+: NYI ( -- ! )
+ "NOT YET IMPLEMENTED!" puts cr -1 fail ;
+
+\ Mark the context as failed with a specific error code. This also
+\ returns control to the caller.
+cc: fail ( err -- ! ) {
+ br_ssl_engine_fail(ENG, (int)T0_POPi());
+ T0_CO();
+}
+
+\ Read a byte from the context (address is offset in context).
+cc: get8 ( addr -- val ) {
+ size_t addr = (size_t)T0_POP();
+ T0_PUSH(*((unsigned char *)ENG + addr));
+}
+
+\ Read a 16-bit word from the context (address is offset in context).
+cc: get16 ( addr -- val ) {
+ size_t addr = (size_t)T0_POP();
+ T0_PUSH(*(uint16_t *)((unsigned char *)ENG + addr));
+}
+
+\ Read a 32-bit word from the context (address is offset in context).
+cc: get32 ( addr -- val ) {
+ size_t addr = (size_t)T0_POP();
+ T0_PUSH(*(uint32_t *)((unsigned char *)ENG + addr));
+}
+
+\ Set a byte in the context (address is offset in context).
+cc: set8 ( val addr -- ) {
+ size_t addr = (size_t)T0_POP();
+ *((unsigned char *)ENG + addr) = (unsigned char)T0_POP();
+}
+
+\ Set a 16-bit word in the context (address is offset in context).
+cc: set16 ( val addr -- ) {
+ size_t addr = (size_t)T0_POP();
+ *(uint16_t *)((unsigned char *)ENG + addr) = (uint16_t)T0_POP();
+}
+
+\ Set a 32-bit word in the context (address is offset in context).
+cc: set32 ( val addr -- ) {
+ size_t addr = (size_t)T0_POP();
+ *(uint32_t *)((unsigned char *)ENG + addr) = (uint32_t)T0_POP();
+}
+
+\ Define a word that evaluates as an address of a field within the
+\ engine context. The field name (C identifier) must follow in the
+\ source. For field 'foo', the defined word is 'addr-foo'.
+: addr-eng:
+ next-word { field }
+ "addr-" field + 0 1 define-word
+ 0 8191 "offsetof(br_ssl_engine_context, " field + ")" + make-CX
+ postpone literal postpone ; ;
+
+addr-eng: max_frag_len
+addr-eng: log_max_frag_len
+addr-eng: peer_log_max_frag_len
+addr-eng: shutdown_recv
+addr-eng: record_type_in
+addr-eng: record_type_out
+addr-eng: version_in
+addr-eng: version_out
+addr-eng: application_data
+addr-eng: version_min
+addr-eng: version_max
+addr-eng: suites_buf
+addr-eng: suites_num
+addr-eng: server_name
+\ addr-eng: version
+\ addr-eng: cipher_suite
+addr-eng: client_random
+addr-eng: server_random
+\ addr-eng: session_id_len
+\ addr-eng: session_id
+addr-eng: ecdhe_curve
+addr-eng: ecdhe_point
+addr-eng: ecdhe_point_len
+addr-eng: reneg
+addr-eng: saved_finished
+addr-eng: pad
+addr-eng: action
+addr-eng: alert
+addr-eng: close_received
+
+\ Similar to 'addr-eng:', for fields in the 'session' substructure.
+: addr-session-field:
+ next-word { field }
+ "addr-" field + 0 1 define-word
+ 0 8191 "offsetof(br_ssl_engine_context, session) + offsetof(br_ssl_session_parameters, " field + ")" + make-CX
+ postpone literal postpone ; ;
+
+addr-session-field: session_id
+addr-session-field: session_id_len
+addr-session-field: version
+addr-session-field: cipher_suite
+addr-session-field: master_secret
+
+\ Define a word that evaluates to an error constant. This assumes that
+\ all relevant error codes are in the 0..63 range.
+: err:
+ next-word { name }
+ name 0 1 define-word
+ 0 63 "BR_" name + make-CX postpone literal postpone ; ;
+
+err: ERR_OK
+err: ERR_BAD_PARAM
+err: ERR_BAD_STATE
+err: ERR_UNSUPPORTED_VERSION
+err: ERR_BAD_VERSION
+err: ERR_BAD_LENGTH
+err: ERR_TOO_LARGE
+err: ERR_BAD_MAC
+err: ERR_NO_RANDOM
+err: ERR_UNKNOWN_TYPE
+err: ERR_UNEXPECTED
+err: ERR_BAD_CCS
+err: ERR_BAD_ALERT
+err: ERR_BAD_HANDSHAKE
+err: ERR_OVERSIZED_ID
+err: ERR_BAD_CIPHER_SUITE
+err: ERR_BAD_COMPRESSION
+err: ERR_BAD_FRAGLEN
+err: ERR_BAD_SECRENEG
+err: ERR_EXTRA_EXTENSION
+err: ERR_BAD_SNI
+err: ERR_BAD_HELLO_DONE
+err: ERR_LIMIT_EXCEEDED
+err: ERR_BAD_FINISHED
+err: ERR_RESUME_MISMATCH
+err: ERR_INVALID_ALGORITHM
+
+\ Get supported curves (bit mask).
+cc: supported-curves ( -- x ) {
+ uint32_t x = ENG->iec == NULL ? 0 : ENG->iec->supported_curves;
+ T0_PUSH(x);
+}
+
+\ Get supported hash functions (bit mask and number).
+cc: supported-hash-functions ( -- x num ) {
+ int i;
+ unsigned x, num;
+
+ x = 0;
+ num = 0;
+ for (i = br_sha1_ID; i <= br_sha512_ID; i ++) {
+ if (br_multihash_getimpl(&ENG->mhash, i)) {
+ x |= 1U << i;
+ num ++;
+ }
+ }
+ T0_PUSH(x);
+ T0_PUSH(num);
+}
+
+\ (Re)initialise the multihasher.
+cc: multihash-init ( -- ) {
+ br_multihash_init(&ENG->mhash);
+}
+
+\ Flush the current record: if some payload data has been accumulated,
+\ close the record and schedule it for sending. If there is no such data,
+\ this function does nothing.
+cc: flush-record ( -- ) {
+ br_ssl_engine_flush_record(ENG);
+}
+
+\ Yield control to the caller.
+\ When the control is returned to us, react to the new context. Returned
+\ value is a bitwise combination of the following:
+\ 0x01 handshake data is available
+\ 0x02 change-cipher-spec data is available
+\ 0x04 some data other than handshake or change-cipher-spec is available
+\ 0x08 output buffer is ready for a new outgoing record
+\ 0x10 renegotiation is requested and not to be ignored
+\ Flags 0x01, 0x02 and 0x04 are mutually exclusive.
+: wait-co ( -- state )
+ co
+ 0
+ addr-action get8 dup if
+ case
+ 1 of 0 do-close endof
+ 2 of addr-application_data get8 if 0x10 or then endof
+ endcase
+ else
+ drop
+ then
+ addr-close_received get8 ifnot
+ has-input? if
+ addr-record_type_in get8 case
+
+ \ ChangeCipherSpec
+ 20 of 0x02 or endof
+
+ \ Alert -- if close_notify received, trigger
+ \ the closure sequence.
+ 21 of process-alerts if -1 do-close then endof
+
+ \ Handshake
+ 22 of 0x01 or endof
+
+ \ Not CCS, Alert or Handshake.
+ drop 0x04 or 0
+ endcase
+ then
+ then
+ can-output? if 0x08 or then ;
+
+\ Send an alert message. This shall be called only when there is room for
+\ an outgoing record.
+: send-alert ( level alert -- )
+ 21 addr-record_type_out set8
+ swap write8-native drop write8-native drop
+ flush-record ;
+
+\ Send an alert message of level "warning". This shall be called only when
+\ there is room for an outgoing record.
+: send-warning ( alert -- )
+ 1 swap send-alert ;
+
+\ Fail by sending a fatal alert.
+: fail-alert ( alert -- ! )
+ { alert }
+ flush-record
+ begin can-output? not while wait-co drop repeat
+ 2 alert send-alert
+ begin can-output? not while wait-co drop repeat
+ alert 512 + fail ;
+
+\ Perform the close operation:
+\ -- Prevent new application data from the caller.
+\ -- Incoming data is discarded (except alerts).
+\ -- Outgoing data is flushed.
+\ -- A close_notify alert is sent.
+\ -- If 'cnr' is zero, then incoming data is discarded until a close_notify
+\ is received.
+\ -- At the end, the context is terminated.
+: do-close ( cnr -- ! )
+ \ 'cnr' is set to non-zero when a close_notify is received from
+ \ the peer.
+ { cnr }
+
+ \ Get out of application data state.
+ 0 addr-application_data set8
+
+ \ Flush existing payload if any.
+ flush-record
+
+ \ Wait for room to send the close_notify. Since individual records
+ \ can always hold at least 512 bytes, we know that when there is
+ \ room, then there is room for a complete close_notify (two bytes).
+ begin can-output? not while cnr wait-for-close >cnr repeat
+
+ \ Write the close_notify and flush it.
+ \ 21 addr-record_type_out set8
+ \ 1 write8-native 0 write8-native 2drop
+ \ flush-record
+ 0 send-warning
+
+ \ Loop until our record has been sent (we know it's gone when
+ \ writing is again possible) and a close_notify has been received.
+ cnr
+ begin
+ dup can-output? and if ERR_OK fail then
+ wait-for-close
+ again ;
+
+\ Yield control to the engine, with a possible flush. If 'cnr' is 0,
+\ then input is analysed: all input is discarded, until a close_notify
+\ is received.
+: wait-for-close ( cnr -- cnr )
+ co
+ dup ifnot
+ has-input? if
+ addr-record_type_in get8 21 = if
+ drop process-alerts
+ else
+ discard-input
+ then
+ then
+ then ;
+
+\ Test whether there is some accumulated payload that still needs to be
+\ sent.
+cc: payload-to-send? ( -- bool ) {
+ T0_PUSHi(-br_ssl_engine_has_pld_to_send(ENG));
+}
+
+\ Test whether there is some available input data.
+cc: has-input? ( -- bool ) {
+ T0_PUSHi(-(ENG->hlen_in != 0));
+}
+
+\ Test whether some payload bytes may be written.
+cc: can-output? ( -- bool ) {
+ T0_PUSHi(-(ENG->hlen_out > 0));
+}
+
+\ Discard current input entirely.
+cc: discard-input ( -- ) {
+ ENG->hlen_in = 0;
+}
+
+\ Low-level read for one byte. If there is no available byte right
+\ away, then -1 is returned. Otherwise, the byte value is returned.
+\ If the current record type is "handshake" then the read byte is also
+\ injected in the multi-hasher.
+cc: read8-native ( -- x ) {
+ if (ENG->hlen_in > 0) {
+ unsigned char x;
+
+ x = *ENG->hbuf_in ++;
+ if (ENG->record_type_in == BR_SSL_HANDSHAKE) {
+ br_multihash_update(&ENG->mhash, &x, 1);
+ }
+ T0_PUSH(x);
+ ENG->hlen_in --;
+ } else {
+ T0_PUSHi(-1);
+ }
+}
+
+\ Low-level read for several bytes. On entry, this expects an address
+\ (offset in the engine context) and a length; these values designate
+\ where the chunk should go. Upon exit, the new address and length
+\ are pushed; that output length contains how many bytes could not be
+\ read. If there is no available byte for reading, the address and
+\ length are unchanged.
+\ If the current record type is "handshake" then the read bytes are
+\ injected in the multi-hasher.
+cc: read-chunk-native ( addr len -- addr len ) {
+ size_t clen = ENG->hlen_in;
+ if (clen > 0) {
+ uint32_t addr, len;
+
+ len = T0_POP();
+ addr = T0_POP();
+ if ((size_t)len < clen) {
+ clen = (size_t)len;
+ }
+ memcpy((unsigned char *)ENG + addr, ENG->hbuf_in, clen);
+ if (ENG->record_type_in == BR_SSL_HANDSHAKE) {
+ br_multihash_update(&ENG->mhash, ENG->hbuf_in, clen);
+ }
+ T0_PUSH(addr + (uint32_t)clen);
+ T0_PUSH(len - (uint32_t)clen);
+ ENG->hbuf_in += clen;
+ ENG->hlen_in -= clen;
+ }
+}
+
+\ Process available alert bytes. If a fatal alert is received, then the
+\ context is terminated; otherwise, this returns either true (-1) if a
+\ close_notify was received, false (0) otherwise.
+: process-alerts ( -- bool )
+ 0
+ begin has-input? while read8-native process-alert-byte or repeat
+ dup if 1 addr-shutdown_recv set8 then ;
+
+\ Process an alert byte. Returned value is non-zero if this is a close_notify,
+\ zero otherwise.
+: process-alert-byte ( x -- bool )
+ addr-alert get8 case
+ 0 of
+ \ 'alert' field is 0, so this byte shall be a level.
+ \ Levels shall be 1 (alert) or 2 (fatal); we convert
+ \ all other values to "fatal".
+ dup 1 <> if drop 2 then
+ addr-alert set8 0
+ endof
+ 1 of
+ 0 addr-alert set8
+ \ close_notify has value 0.
+ 0= ret
+ endof
+ \ Fatal alert implies context termination.
+ 256 + fail
+ endcase ;
+
+\ In general we only deal with handshake data here. Alerts are processed
+\ in specific code right when they are received, and ChangeCipherSpec has
+\ its own handling code. So we need to check that the data is "handshake"
+\ only when returning from a coroutine call.
+
+\ Yield control to the engine. Alerts are processed; if incoming data is
+\ neither handshake or alert, then an error is triggered.
+: wait-for-handshake ( -- )
+ wait-co 0x07 and 0x01 > if ERR_UNEXPECTED fail then ;
+
+\ Flush outgoing data (if any), then wait for the output buffer to be
+\ clear; when this is done, set the output record type to the specified
+\ value.
+: wait-rectype-out ( rectype -- )
+ { rectype }
+ flush-record
+ begin
+ can-output? if rectype addr-record_type_out set8 ret then
+ wait-co drop
+ again ;
+
+\ Read one byte of handshake data. Block until that byte is available.
+\ This does not check any length.
+: read8-nc ( -- x )
+ begin
+ read8-native dup 0< ifnot ret then
+ drop wait-for-handshake
+ again ;
+
+\ Test whether there are some more bytes in the current record. These
+\ bytes have not necessarily been received yet (processing of unencrypted
+\ records may begin before all bytes are received).
+cc: more-incoming-bytes? ( -- bool ) {
+ T0_PUSHi(ENG->hlen_in != 0 || !br_ssl_engine_recvrec_finished(ENG));
+}
+
+\ For reading functions, the TOS is supposed to contain the number of bytes
+\ that can still be read (from encapsulating structure header), and it is
+\ updated.
+
+: check-len ( lim len -- lim )
+ - dup 0< if ERR_BAD_PARAM fail then ;
+
+\ Read one byte of handshake data. This pushes an integer in the 0..255 range.
+: read8 ( lim -- lim x )
+ 1 check-len read8-nc ;
+
+\ Read a 16-bit value (in the 0..65535 range)
+: read16 ( lim -- lim n )
+ 2 check-len read8-nc 8 << read8-nc + ;
+
+\ Read a 24-bit value (in the 0..16777215 range)
+: read24 ( lim -- lim n )
+ 3 check-len read8-nc 8 << read8-nc + 8 << read8-nc + ;
+
+\ Read some bytes. The "address" is an offset within the context
+\ structure.
+: read-blob ( lim addr len -- lim )
+ { addr len }
+ len check-len
+ addr len
+ begin
+ read-chunk-native
+ dup 0 = if 2drop ret then
+ wait-for-handshake
+ again ;
+
+\ Read some bytes and drop them.
+: skip-blob ( lim len -- lim )
+ swap over check-len swap
+ begin dup while read8-nc drop 1- repeat
+ drop ;
+
+\ Read a 16-bit length, then skip exactly that many bytes.
+: read-ignore-16 ( lim -- lim )
+ read16 skip-blob ;
+
+\ Open a substructure: the inner structure length is checked against,
+\ and substracted, from the output structure current limit.
+: open-elt ( lim len -- lim-outer lim-inner )
+ dup { len }
+ - dup 0< if ERR_BAD_PARAM fail then
+ len ;
+
+\ Close the current structure. This checks that the limit is 0.
+: close-elt ( lim -- )
+ if ERR_BAD_PARAM fail then ;
+
+\ Write one byte of handshake data.
+: write8 ( n -- )
+ begin
+ dup write8-native if drop ret then
+ wait-co drop
+ again ;
+
+\ Low-level write for one byte. On exit, it pushes either -1 (byte was
+\ written) or 0 (no room in output buffer).
+cc: write8-native ( x -- bool ) {
+ unsigned char x;
+
+ x = (unsigned char)T0_POP();
+ if (ENG->hlen_out > 0) {
+ if (ENG->record_type_out == BR_SSL_HANDSHAKE) {
+ br_multihash_update(&ENG->mhash, &x, 1);
+ }
+ *ENG->hbuf_out ++ = x;
+ ENG->hlen_out --;
+ T0_PUSHi(-1);
+ } else {
+ T0_PUSHi(0);
+ }
+}
+
+\ Write a 16-bit value.
+: write16 ( n -- )
+ dup 8 u>> write8 write8 ;
+
+\ Write a 24-bit value.
+: write24 ( n -- )
+ dup 16 u>> write8 write16 ;
+
+\ Write some bytes. The "address" is an offset within the context
+\ structure.
+: write-blob ( addr len -- )
+ begin
+ write-blob-chunk
+ dup 0 = if 2drop ret then
+ wait-co drop
+ again ;
+
+cc: write-blob-chunk ( addr len -- addr len ) {
+ size_t clen = ENG->hlen_out;
+ if (clen > 0) {
+ uint32_t addr, len;
+
+ len = T0_POP();
+ addr = T0_POP();
+ if ((size_t)len < clen) {
+ clen = (size_t)len;
+ }
+ memcpy(ENG->hbuf_out, (unsigned char *)ENG + addr, clen);
+ if (ENG->record_type_out == BR_SSL_HANDSHAKE) {
+ br_multihash_update(&ENG->mhash, ENG->hbuf_out, clen);
+ }
+ T0_PUSH(addr + (uint32_t)clen);
+ T0_PUSH(len - (uint32_t)clen);
+ ENG->hbuf_out += clen;
+ ENG->hlen_out -= clen;
+ }
+}
+
+\ Write a blob with the length as header (over one byte)
+: write-blob-head8 ( addr len -- )
+ dup write8 write-blob ;
+
+\ Write a blob with the length as header (over two bytes)
+: write-blob-head16 ( addr len -- )
+ dup write16 write-blob ;
+
+\ Perform a byte-to-byte comparison between two blobs. Each blob is
+\ provided as an "address" (offset in the context structure); the
+\ length is common. Returned value is true (-1) if the two blobs are
+\ equal, false (0) otherwise.
+cc: memcmp ( addr1 addr2 len -- bool ) {
+ size_t len = (size_t)T0_POP();
+ void *addr2 = (unsigned char *)ENG + (size_t)T0_POP();
+ void *addr1 = (unsigned char *)ENG + (size_t)T0_POP();
+ int x = memcmp(addr1, addr2, len);
+ T0_PUSH((uint32_t)-(x == 0));
+}
+
+\ Copy bytes between two areas, whose addresses are provided as
+\ offsets in the context structure.
+cc: memcpy ( dst src len -- ) {
+ size_t len = (size_t)T0_POP();
+ void *src = (unsigned char *)ENG + (size_t)T0_POP();
+ void *dst = (unsigned char *)ENG + (size_t)T0_POP();
+ memcpy(dst, src, len);
+}
+
+\ Get string length (zero-terminated). The string address is provided as
+\ an offset relative to the context start. Returned length does not include
+\ the terminated 0.
+cc: strlen ( str -- len ) {
+ void *str = (unsigned char *)ENG + (size_t)T0_POP();
+ T0_PUSH((uint32_t)strlen(str));
+}
+
+\ Fill a buffer with zeros. The buffer address is an offset in the context.
+cc: bzero ( addr len -- ) {
+ size_t len = (size_t)T0_POP();
+ void *addr = (unsigned char *)ENG + (size_t)T0_POP();
+ memset(addr, 0, len);
+}
+
+\ Scan the list of supported cipher suites for a given value. If found,
+\ then the list index at which it was found is returned; otherwise, -1
+\ is returned.
+: scan-suite ( suite -- index )
+ { suite }
+ addr-suites_num get8 { num }
+ 0
+ begin dup num < while
+ dup 1 << addr-suites_buf + get16 suite = if ret then
+ 1+
+ repeat
+ drop -1 ;
+
+\ =======================================================================
+
+\ Generate random bytes into buffer (address is offset in context).
+cc: mkrand ( addr len -- ) {
+ size_t len = (size_t)T0_POP();
+ void *addr = (unsigned char *)ENG + (size_t)T0_POP();
+ br_hmac_drbg_generate(&ENG->rng, addr, len);
+}
+
+\ Read a handshake message header: type and length. These are returned
+\ in reverse order (type is TOS, length is below it).
+: read-handshake-header-core ( -- lim type )
+ read8-nc 3 read24 swap drop swap ;
+
+\ Read a handshake message header: type and length. If the header is for
+\ a HelloRequest message, then it is discarded and a new header is read
+\ (repeatedly if necessary).
+: read-handshake-header ( -- lim type )
+ begin
+ read-handshake-header-core dup 0= while
+ drop if ERR_BAD_HANDSHAKE fail then
+ repeat ;
+
+\ =======================================================================
+
+\ Cipher suite processing.
+\
+\ Unfortunately, cipher suite identifiers are attributed mostly arbitrary,
+\ so we have to map the cipher suite numbers we support into aggregate
+\ words that encode the information we need. Table below is organized
+\ as a sequence of pairs of 16-bit words, the first being the cipher suite
+\ identifier, the second encoding the algorithm elements. The suites are
+\ ordered by increasing cipher suite ID, so that fast lookups may be
+\ performed with a binary search (not implemented for the moment, since it
+\ does not appear to matter much in practice).
+\
+\ Algorithm elements are encoded over 4 bits each, in the following order
+\ (most significant to least significant):
+\
+\ -- Server key type:
+\ 0 RSA (RSA key exchange)
+\ 1 ECDHE-RSA (ECDHE key exchange, RSA signature)
+\ 2 ECDHE-ECDSA (ECDHE key exchange, ECDSA signature)
+\ 3 ECDH-RSA (ECDH key exchange, certificate is RSA-signed)
+\ 4 ECDH-ECDSA (ECDH key exchange, certificate is ECDSA-signed)
+\ -- Encryption algorithm:
+\ 0 3DES/CBC
+\ 1 AES-128/CBC
+\ 2 AES-256/CBC
+\ 3 AES-128/GCM
+\ 4 AES-256/GCM
+\ 5 ChaCha20/Poly1305
+\ -- MAC algorithm:
+\ 0 none (for suites with AEAD encryption)
+\ 2 HMAC/SHA-1
+\ 4 HMAC/SHA-256
+\ 5 HMAC/SHA-384
+\ -- PRF for TLS-1.2:
+\ 4 with SHA-256
+\ 5 with SHA-384
+
+data: cipher-suite-def
+
+hexb| 000A 0024 | \ TLS_RSA_WITH_3DES_EDE_CBC_SHA
+hexb| 002F 0124 | \ TLS_RSA_WITH_AES_128_CBC_SHA
+hexb| 0035 0224 | \ TLS_RSA_WITH_AES_256_CBC_SHA
+hexb| 003C 0144 | \ TLS_RSA_WITH_AES_128_CBC_SHA256
+hexb| 003D 0244 | \ TLS_RSA_WITH_AES_256_CBC_SHA256
+
+hexb| 009C 0304 | \ TLS_RSA_WITH_AES_128_GCM_SHA256
+hexb| 009D 0405 | \ TLS_RSA_WITH_AES_256_GCM_SHA384
+
+hexb| C003 4024 | \ TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
+hexb| C004 4124 | \ TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
+hexb| C005 4224 | \ TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
+hexb| C008 2024 | \ TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
+hexb| C009 2124 | \ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
+hexb| C00A 2224 | \ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
+hexb| C00D 3024 | \ TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA
+hexb| C00E 3124 | \ TLS_ECDH_RSA_WITH_AES_128_CBC_SHA
+hexb| C00F 3224 | \ TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
+hexb| C012 1024 | \ TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
+hexb| C013 1124 | \ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
+hexb| C014 1224 | \ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
+
+hexb| C023 2144 | \ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
+hexb| C024 2255 | \ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
+hexb| C025 4144 | \ TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
+hexb| C026 4255 | \ TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
+hexb| C027 1144 | \ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
+hexb| C028 1255 | \ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
+hexb| C029 3144 | \ TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
+hexb| C02A 3255 | \ TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
+hexb| C02B 2304 | \ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
+hexb| C02C 2405 | \ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
+hexb| C02D 4304 | \ TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
+hexb| C02E 4405 | \ TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384
+hexb| C02F 1304 | \ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+hexb| C030 1405 | \ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
+hexb| C031 3304 | \ TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
+hexb| C032 3405 | \ TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
+
+hexb| CCA8 1504 | \ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
+hexb| CCA9 2504 | \ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
+
+hexb| 0000 | \ List terminator.
+
+\ Convert cipher suite identifier to element words. This returns 0 if
+\ the cipher suite is not known.
+: cipher-suite-to-elements ( suite -- elts )
+ { id }
+ cipher-suite-def
+ begin
+ dup 2+ swap data-get16
+ dup ifnot 2drop 0 ret then
+ id = if data-get16 ret then
+ 2+
+ again ;
+
+\ Check that a given cipher suite is supported.
+: suite-supported? ( suite -- bool )
+ cipher-suite-to-elements 0<> ;
+
+\ Get expected key type for cipher suite. The key type is one of
+\ BR_KEYTYPE_RSA or BR_KEYTYPE_EC, combined with either BR_KEYTYPE_KEYX
+\ (RSA encryption or static ECDH) or BR_KEYTYPE_SIGN (RSA or ECDSA
+\ signature, for ECDHE cipher suites).
+: expected-key-type ( suite -- key-type )
+ cipher-suite-to-elements 12 >>
+ case
+ 0 of CX 0 63 { BR_KEYTYPE_RSA | BR_KEYTYPE_KEYX } endof
+ 1 of CX 0 63 { BR_KEYTYPE_RSA | BR_KEYTYPE_SIGN } endof
+ 2 of CX 0 63 { BR_KEYTYPE_EC | BR_KEYTYPE_SIGN } endof
+ 3 of CX 0 63 { BR_KEYTYPE_EC | BR_KEYTYPE_KEYX } endof
+ 4 of CX 0 63 { BR_KEYTYPE_EC | BR_KEYTYPE_KEYX } endof
+ 0 swap
+ endcase ;
+
+\ Test whether the cipher suite uses RSA key exchange.
+: use-rsa-keyx? ( suite -- bool )
+ cipher-suite-to-elements 12 >> 0= ;
+
+\ Test whether the cipher suite uses ECDHE key exchange, signed with RSA.
+: use-rsa-ecdhe? ( suite -- bool )
+ cipher-suite-to-elements 12 >> 1 = ;
+
+\ Test whether the cipher suite uses ECDHE key exchange, signed with ECDSA.
+: use-ecdsa-ecdhe? ( suite -- bool )
+ cipher-suite-to-elements 12 >> 2 = ;
+
+\ Test whether the cipher suite uses ECDHE key exchange (with RSA or ECDSA).
+: use-ecdhe? ( suite -- bool )
+ cipher-suite-to-elements 12 >> dup 0> swap 3 < and ;
+
+\ Test whether the cipher suite uses ECDH (static) key exchange.
+: use-ecdh? ( suite -- bool )
+ cipher-suite-to-elements 12 >> 2 > ;
+
+\ Get identifier for the PRF (TLS 1.2).
+: prf-id ( suite -- id )
+ cipher-suite-to-elements 15 and ;
+
+\ Switch to negotiated security parameters for input or output.
+: switch-encryption ( is-client for-input -- )
+ { for-input }
+ addr-cipher_suite get16 cipher-suite-to-elements { elts }
+
+ \ prf_id
+ elts 15 and
+
+ \ mac_id
+ elts 4 >> 15 and
+
+ \ cipher type and key length
+ elts 8 >> 15 and case
+ \ 3DES/CBC
+ 0 of 0 24
+ for-input if
+ switch-cbc-in
+ else
+ switch-cbc-out
+ then
+ endof
+
+ \ AES-128/CBC
+ 1 of 1 16
+ for-input if
+ switch-cbc-in
+ else
+ switch-cbc-out
+ then
+ endof
+
+ \ AES-256/CBC
+ 2 of 1 32
+ for-input if
+ switch-cbc-in
+ else
+ switch-cbc-out
+ then
+ endof
+
+ \ AES-128/GCM
+ 3 of drop 16
+ for-input if
+ switch-aesgcm-in
+ else
+ switch-aesgcm-out
+ then
+ endof
+
+ \ AES-256/GCM
+ 4 of drop 32
+ for-input if
+ switch-aesgcm-in
+ else
+ switch-aesgcm-out
+ then
+ endof
+
+ \ ChaCha20/Poly1305
+ \ 5 of endof
+
+ ERR_BAD_PARAM fail
+ endcase
+ ;
+
+cc: switch-cbc-out ( is_client prf_id mac_id aes cipher_key_len -- ) {
+ int is_client, prf_id, mac_id, aes;
+ unsigned cipher_key_len;
+
+ cipher_key_len = T0_POP();
+ aes = T0_POP();
+ mac_id = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_cbc_out(ENG, is_client, prf_id, mac_id,
+ aes ? ENG->iaes_cbcenc : ENG->ides_cbcenc, cipher_key_len);
+}
+
+cc: switch-cbc-in ( is_client prf_id mac_id aes cipher_key_len -- ) {
+ int is_client, prf_id, mac_id, aes;
+ unsigned cipher_key_len;
+
+ cipher_key_len = T0_POP();
+ aes = T0_POP();
+ mac_id = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_cbc_in(ENG, is_client, prf_id, mac_id,
+ aes ? ENG->iaes_cbcdec : ENG->ides_cbcdec, cipher_key_len);
+}
+
+cc: switch-aesgcm-out ( is_client prf_id cipher_key_len -- ) {
+ int is_client, prf_id;
+ unsigned cipher_key_len;
+
+ cipher_key_len = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_gcm_out(ENG, is_client, prf_id,
+ ENG->iaes_ctr, cipher_key_len);
+}
+
+cc: switch-aesgcm-in ( is_client prf_id cipher_key_len -- ) {
+ int is_client, prf_id;
+ unsigned cipher_key_len;
+
+ cipher_key_len = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_gcm_in(ENG, is_client, prf_id,
+ ENG->iaes_ctr, cipher_key_len);
+}
+
+\ Write Finished message.
+: write-Finished ( from_client -- )
+ compute-Finished
+ 20 write8 12 write24 addr-pad 12 write-blob ;
+
+\ Read Finished message.
+: read-Finished ( from_client -- )
+ compute-Finished
+ read-handshake-header 20 <> if ERR_UNEXPECTED fail then
+ addr-pad 12 + 12 read-blob
+ close-elt
+ addr-pad dup 12 + 12 memcmp ifnot ERR_BAD_FINISHED fail then ;
+
+\ Compute the "Finished" contents (either the value to send, or the
+\ expected value). The 12-byte string is written in the pad. The
+\ "from_client" value is non-zero for the Finished sent by the client.
+\ The computed value is also saved in the relevant buffer for handling
+\ secure renegotiation.
+: compute-Finished ( from_client -- )
+ dup addr-saved_finished swap ifnot 12 + then swap
+ addr-cipher_suite get16 prf-id compute-Finished-inner
+ addr-pad 12 memcpy ;
+
+cc: compute-Finished-inner ( from_client prf_id -- ) {
+ int prf_id = T0_POP();
+ int from_client = T0_POPi();
+ unsigned char seed[48];
+ size_t seed_len;
+
+ br_tls_prf_impl prf = br_ssl_engine_get_PRF(ENG, prf_id);
+ if (ENG->session.version >= BR_TLS12) {
+ seed_len = br_multihash_out(&ENG->mhash, prf_id, seed);
+ } else {
+ br_multihash_out(&ENG->mhash, br_md5_ID, seed);
+ br_multihash_out(&ENG->mhash, br_sha1_ID, seed + 16);
+ seed_len = 36;
+ }
+ prf(ENG->pad, 12, ENG->session.master_secret,
+ sizeof ENG->session.master_secret,
+ from_client ? "client finished" : "server finished",
+ seed, seed_len);
+}
+
+\ Receive ChangeCipherSpec and Finished from the peer.
+: read-CCS-Finished ( is-client -- )
+ has-input? if
+ addr-record_type_in get8 20 <> if ERR_UNEXPECTED fail then
+ else
+ begin
+ wait-co 0x07 and dup 0x02 <> while
+ if ERR_UNEXPECTED fail then
+ repeat
+ drop
+ then
+ read8-nc 1 <> more-incoming-bytes? or if ERR_BAD_CCS fail then
+ dup 1 switch-encryption
+
+ \ Read and verify Finished from peer.
+ not read-Finished ;
+
+\ Send ChangeCipherSpec and Finished to the peer.
+: write-CCS-Finished ( is-client -- )
+ \ Flush and wait for output buffer to be clear, so that we may
+ \ write our ChangeCipherSpec. We must switch immediately after
+ \ triggering the flush.
+ 20 wait-rectype-out
+ 1 write8
+ flush-record
+ dup 0 switch-encryption
+ 22 wait-rectype-out
+ write-Finished
+ flush-record ;
--- /dev/null
+/* 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 uint8_t t0_datablock[];
+
+
+void br_ssl_hs_server_init_main(void *t0ctx);
+
+void br_ssl_hs_server_run(void *t0ctx);
+
+
+
+#include <stddef.h>
+#include <string.h>
+
+#include "inner.h"
+
+/*
+ * This macro evaluates to a pointer to the current engine context.
+ */
+#define ENG ((br_ssl_engine_context *)((unsigned char *)t0ctx - offsetof(br_ssl_engine_context, cpu)))
+
+
+
+
+
+/*
+ * This macro evaluates to a pointer to the server context, under that
+ * specific name. It must be noted that since the engine context is the
+ * first field of the br_ssl_server_context structure ('eng'), then
+ * pointers values of both types are interchangeable, modulo an
+ * appropriate cast. This also means that "adresses" computed as offsets
+ * within the structure work for both kinds of context.
+ */
+#define CTX ((br_ssl_server_context *)ENG)
+
+/*
+ * Decrypt the pre-master secret (RSA key exchange).
+ */
+static void
+do_rsa_decrypt(br_ssl_server_context *ctx, int prf_id,
+ unsigned char *epms, size_t len)
+{
+ uint32_t x;
+ unsigned char rpms[48];
+
+ /*
+ * Decrypt the PMS.
+ */
+ x = (*ctx->policy_vtable)->do_keyx(ctx->policy_vtable, epms, len);
+
+ /*
+ * Set the first two bytes to the maximum supported client
+ * protocol version. These bytes are used for version rollback
+ * detection; forceing the two bytes will make the master secret
+ * wrong if the bytes are not correct. This process is
+ * recommended by RFC 5246 (section 7.4.7.1).
+ */
+ br_enc16be(epms, ctx->client_max_version);
+
+ /*
+ * Make a random PMS and copy it above the decrypted value if the
+ * decryption failed. Note that we use a constant-time conditional
+ * copy.
+ */
+ br_hmac_drbg_generate(&ctx->eng.rng, rpms, sizeof rpms);
+ br_ccopy(x ^ 1, epms, rpms, sizeof rpms);
+
+ /*
+ * Compute master secret.
+ */
+ br_ssl_engine_compute_master(&ctx->eng, prf_id, epms, 48);
+
+ /*
+ * Clear the pre-master secret from RAM: it is normally a buffer
+ * in the context, hence potentially long-lived.
+ */
+ memset(epms, 0, len);
+}
+
+/*
+ * Common part for ECDH and ECDHE.
+ */
+static void
+ecdh_common(br_ssl_server_context *ctx, int prf_id,
+ unsigned char *cpoint, size_t cpoint_len, uint32_t ctl)
+{
+ unsigned char rpms[80];
+ size_t pms_len;
+
+ /*
+ * The point length is supposed to be 1+2*Xlen, where Xlen is
+ * the length (in bytes) of the X coordinate, i.e. the pre-master
+ * secret. If the provided point is too large, then it is
+ * obviously incorrect (i.e. everybody can see that it is
+ * incorrect), so leaking that fact is not a problem.
+ */
+ pms_len = cpoint_len >> 1;
+ if (pms_len > sizeof rpms) {
+ pms_len = sizeof rpms;
+ ctl = 0;
+ }
+
+ /*
+ * Make a random PMS and copy it above the decrypted value if the
+ * decryption failed. Note that we use a constant-time conditional
+ * copy.
+ */
+ br_hmac_drbg_generate(&ctx->eng.rng, rpms, pms_len);
+ br_ccopy(ctl ^ 1, cpoint + 1, rpms, pms_len);
+
+ /*
+ * Compute master secret.
+ */
+ br_ssl_engine_compute_master(&ctx->eng, prf_id, cpoint + 1, pms_len);
+
+ /*
+ * Clear the pre-master secret from RAM: it is normally a buffer
+ * in the context, hence potentially long-lived.
+ */
+ memset(cpoint, 0, cpoint_len);
+}
+
+/*
+ * Do the ECDH key exchange (not ECDHE).
+ */
+static void
+do_ecdh(br_ssl_server_context *ctx, int prf_id,
+ unsigned char *cpoint, size_t cpoint_len)
+{
+ uint32_t x;
+
+ /*
+ * Finalise the key exchange.
+ */
+ x = (*ctx->policy_vtable)->do_keyx(ctx->policy_vtable,
+ cpoint, cpoint_len);
+ ecdh_common(ctx, prf_id, cpoint, cpoint_len, x);
+}
+
+/*
+ * Do the ECDHE key exchange (part 1: generation of transient key, and
+ * computing of the point to send to the client). Returned value is the
+ * signature length (in bytes), or -x on error (with x being an error
+ * code). The encoded point is written in the ecdhe_point[] context buffer
+ * (length in ecdhe_point_len).
+ */
+static int
+do_ecdhe_part1(br_ssl_server_context *ctx, int curve)
+{
+ int hash;
+ unsigned mask;
+ const unsigned char *order, *generator;
+ size_t olen, glen;
+ br_multihash_context mhc;
+ unsigned char head[4];
+ size_t hv_len, sig_len;
+
+ if (!((ctx->eng.iec->supported_curves >> curve) & 1)) {
+ return -BR_ERR_INVALID_ALGORITHM;
+ }
+ ctx->eng.ecdhe_curve = curve;
+
+ /*
+ * Generate our private key. We need a non-zero random value
+ * which is lower than the curve order, in a "large enough"
+ * range. We force the top bit to 0 and bottom bit to 1, which
+ * does the trick. Note that contrary to what happens in ECDSA,
+ * this is not a problem if we do not cover the full range of
+ * possible values.
+ */
+ order = ctx->eng.iec->order(curve, &olen);
+ mask = 0xFF;
+ while (mask >= order[0]) {
+ mask >>= 1;
+ }
+ br_hmac_drbg_generate(&ctx->eng.rng, ctx->ecdhe_key, olen);
+ ctx->ecdhe_key[0] &= mask;
+ ctx->ecdhe_key[olen - 1] |= 0x01;
+ ctx->ecdhe_key_len = olen;
+
+ /*
+ * Compute our ECDH point.
+ */
+ generator = ctx->eng.iec->generator(curve, &glen);
+ memcpy(ctx->eng.ecdhe_point, generator, glen);
+ ctx->eng.ecdhe_point_len = glen;
+ if (!ctx->eng.iec->mul(ctx->eng.ecdhe_point, glen,
+ ctx->ecdhe_key, olen, curve))
+ {
+ return -BR_ERR_INVALID_ALGORITHM;
+ }
+
+ /*
+ * Compute the signature.
+ */
+ br_multihash_zero(&mhc);
+ br_multihash_copyimpl(&mhc, &ctx->eng.mhash);
+ br_multihash_init(&mhc);
+ br_multihash_update(&mhc,
+ ctx->eng.client_random, sizeof ctx->eng.client_random);
+ br_multihash_update(&mhc,
+ ctx->eng.server_random, sizeof ctx->eng.server_random);
+ head[0] = 3;
+ head[1] = 0;
+ head[2] = curve;
+ head[3] = ctx->eng.ecdhe_point_len;
+ br_multihash_update(&mhc, head, sizeof head);
+ br_multihash_update(&mhc,
+ ctx->eng.ecdhe_point, ctx->eng.ecdhe_point_len);
+ hash = ctx->sign_hash_id;
+ if (hash) {
+ hv_len = br_multihash_out(&mhc, hash, ctx->eng.pad);
+ if (hv_len == 0) {
+ return -BR_ERR_INVALID_ALGORITHM;
+ }
+ } else {
+ if (!br_multihash_out(&mhc, br_md5_ID, ctx->eng.pad)
+ || !br_multihash_out(&mhc,
+ br_sha1_ID, ctx->eng.pad + 16))
+ {
+ return -BR_ERR_INVALID_ALGORITHM;
+ }
+ hv_len = 36;
+ }
+ sig_len = (*ctx->policy_vtable)->do_sign(ctx->policy_vtable,
+ hash, hv_len, ctx->eng.pad, sizeof ctx->eng.pad);
+ return sig_len ? (int)sig_len : -BR_ERR_INVALID_ALGORITHM;
+}
+
+/*
+ * Do the ECDHE key exchange (part 2: computation of the shared secret
+ * from the point sent by the client).
+ */
+static void
+do_ecdhe_part2(br_ssl_server_context *ctx, int prf_id,
+ unsigned char *cpoint, size_t cpoint_len)
+{
+ int curve;
+ uint32_t x;
+
+ curve = ctx->eng.ecdhe_curve;
+
+ /*
+ * Finalise the key exchange.
+ */
+ x = ctx->eng.iec->mul(cpoint, cpoint_len,
+ ctx->ecdhe_key, ctx->ecdhe_key_len, curve);
+ ecdh_common(ctx, prf_id, cpoint, cpoint_len, x);
+
+ /*
+ * Clear the ECDHE private key. Forward Secrecy is achieved insofar
+ * as that key does not get stolen, so we'd better destroy it
+ * as soon as it ceases to be useful.
+ */
+ memset(ctx->ecdhe_key, 0, ctx->ecdhe_key_len);
+}
+
+
+
+static const uint8_t t0_datablock[] = {
+ 0x00, 0x00, 0x0A, 0x00, 0x24, 0x00, 0x2F, 0x01, 0x24, 0x00, 0x35, 0x02,
+ 0x24, 0x00, 0x3C, 0x01, 0x44, 0x00, 0x3D, 0x02, 0x44, 0x00, 0x9C, 0x03,
+ 0x04, 0x00, 0x9D, 0x04, 0x05, 0xC0, 0x03, 0x40, 0x24, 0xC0, 0x04, 0x41,
+ 0x24, 0xC0, 0x05, 0x42, 0x24, 0xC0, 0x08, 0x20, 0x24, 0xC0, 0x09, 0x21,
+ 0x24, 0xC0, 0x0A, 0x22, 0x24, 0xC0, 0x0D, 0x30, 0x24, 0xC0, 0x0E, 0x31,
+ 0x24, 0xC0, 0x0F, 0x32, 0x24, 0xC0, 0x12, 0x10, 0x24, 0xC0, 0x13, 0x11,
+ 0x24, 0xC0, 0x14, 0x12, 0x24, 0xC0, 0x23, 0x21, 0x44, 0xC0, 0x24, 0x22,
+ 0x55, 0xC0, 0x25, 0x41, 0x44, 0xC0, 0x26, 0x42, 0x55, 0xC0, 0x27, 0x11,
+ 0x44, 0xC0, 0x28, 0x12, 0x55, 0xC0, 0x29, 0x31, 0x44, 0xC0, 0x2A, 0x32,
+ 0x55, 0xC0, 0x2B, 0x23, 0x04, 0xC0, 0x2C, 0x24, 0x05, 0xC0, 0x2D, 0x43,
+ 0x04, 0xC0, 0x2E, 0x44, 0x05, 0xC0, 0x2F, 0x13, 0x04, 0xC0, 0x30, 0x14,
+ 0x05, 0xC0, 0x31, 0x33, 0x04, 0xC0, 0x32, 0x34, 0x05, 0xCC, 0xA8, 0x15,
+ 0x04, 0xCC, 0xA9, 0x25, 0x04, 0x00, 0x00
+};
+
+static const uint8_t t0_codeblock[] = {
+ 0x00, 0x01, 0x00, 0x0A, 0x00, 0x00, 0x01, 0x00, 0x0D, 0x00, 0x00, 0x01,
+ 0x00, 0x0E, 0x00, 0x00, 0x01, 0x00, 0x0F, 0x00, 0x00, 0x01, 0x01, 0x08,
+ 0x00, 0x00, 0x01, 0x01, 0x09, 0x00, 0x00, 0x01, 0x02, 0x08, 0x00, 0x00,
+ 0x21, 0x21, 0x00, 0x00, 0x01, T0_INT1(BR_ERR_BAD_CCS), 0x00, 0x00,
+ 0x01, T0_INT1(BR_ERR_BAD_FINISHED), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_BAD_FRAGLEN), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_BAD_HANDSHAKE), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_BAD_PARAM), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_BAD_SECRENEG), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_BAD_VERSION), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_LIMIT_EXCEEDED), 0x00, 0x00, 0x01, T0_INT1(BR_ERR_OK),
+ 0x00, 0x00, 0x01, T0_INT1(BR_ERR_OVERSIZED_ID), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_UNEXPECTED), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, action)), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, alert)), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, application_data)), 0x00, 0x00,
+ 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, session) + offsetof(br_ssl_session_parameters, cipher_suite)),
+ 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_server_context, client_max_version)), 0x00,
+ 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, client_random)),
+ 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_server_context, client_suites)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(br_ssl_server_context, client_suites_num)),
+ 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, close_received)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(br_ssl_server_context, curves)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(br_ssl_engine_context, ecdhe_point)), 0x00,
+ 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, ecdhe_point_len)),
+ 0x00, 0x00, 0x01, T0_INT2(offsetof(br_ssl_server_context, flags)),
+ 0x00, 0x00, 0x01, T0_INT2(offsetof(br_ssl_server_context, hashes)),
+ 0x00, 0x00, 0x5D, 0x01,
+ T0_INT2(BR_MAX_CIPHER_SUITES * sizeof(br_suite_translated)), 0x00,
+ 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, log_max_frag_len)),
+ 0x00, 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, pad)), 0x00,
+ 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, peer_log_max_frag_len)), 0x00,
+ 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, record_type_in)),
+ 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, record_type_out)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(br_ssl_engine_context, reneg)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(br_ssl_engine_context, saved_finished)), 0x00,
+ 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, server_name)),
+ 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, server_random)), 0x00, 0x00,
+ 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, session) + offsetof(br_ssl_session_parameters, session_id)),
+ 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, session) + offsetof(br_ssl_session_parameters, session_id_len)),
+ 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, shutdown_recv)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(br_ssl_server_context, sign_hash_id)), 0x00,
+ 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, suites_buf)), 0x00,
+ 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, suites_num)), 0x00,
+ 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, session) + offsetof(br_ssl_session_parameters, version)),
+ 0x00, 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, version_in)),
+ 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, version_max)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(br_ssl_engine_context, version_min)), 0x00,
+ 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, version_out)),
+ 0x00, 0x00, 0x09, 0x22, 0x44, 0x06, 0x02, 0x50, 0x23, 0x00, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x03, 0x00, 0x7B, 0x22, 0x4A, 0x3B, 0x7F, 0x22, 0x05,
+ 0x04, 0x4B, 0x01, 0x00, 0x00, 0x02, 0x00, 0x0E, 0x06, 0x02, 0x7F, 0x00,
+ 0x4A, 0x04, 0x6B, 0x00, 0x06, 0x02, 0x50, 0x23, 0x00, 0x00, 0x22, 0x6C,
+ 0x3B, 0x05, 0x03, 0x01, 0x0C, 0x08, 0x3B, 0x5A, 0x25, 0x81, 0x07, 0x19,
+ 0x67, 0x01, 0x0C, 0x2A, 0x00, 0x00, 0x22, 0x1B, 0x01, 0x08, 0x0B, 0x3B,
+ 0x48, 0x1B, 0x08, 0x00, 0x01, 0x03, 0x00, 0x01, 0x00, 0x59, 0x38, 0x24,
+ 0x16, 0x2F, 0x06, 0x08, 0x02, 0x00, 0x81, 0x26, 0x03, 0x00, 0x04, 0x74,
+ 0x01, 0x00, 0x81, 0x1E, 0x02, 0x00, 0x22, 0x16, 0x12, 0x06, 0x02, 0x54,
+ 0x23, 0x81, 0x26, 0x04, 0x75, 0x00, 0x01, 0x00, 0x59, 0x38, 0x01, 0x16,
+ 0x6A, 0x38, 0x2D, 0x81, 0x0B, 0x2C, 0x06, 0x02, 0x56, 0x23, 0x06, 0x0C,
+ 0x81, 0x2C, 0x01, 0x00, 0x81, 0x29, 0x01, 0x00, 0x81, 0x0A, 0x04, 0x14,
+ 0x81, 0x2C, 0x81, 0x2A, 0x81, 0x2E, 0x81, 0x2D, 0x24, 0x81, 0x0C, 0x01,
+ 0x00, 0x81, 0x0A, 0x01, 0x00, 0x81, 0x29, 0x34, 0x01, 0x01, 0x59, 0x38,
+ 0x01, 0x17, 0x6A, 0x38, 0x00, 0x00, 0x31, 0x31, 0x00, 0x01, 0x03, 0x00,
+ 0x24, 0x16, 0x2F, 0x06, 0x05, 0x81, 0x25, 0x21, 0x04, 0x77, 0x01, 0x02,
+ 0x02, 0x00, 0x81, 0x1D, 0x16, 0x2F, 0x06, 0x05, 0x81, 0x25, 0x21, 0x04,
+ 0x77, 0x02, 0x00, 0x01, 0x84, 0x00, 0x08, 0x23, 0x00, 0x00, 0x63, 0x26,
+ 0x3B, 0x11, 0x01, 0x01, 0x12, 0x2E, 0x00, 0x00, 0x01, 0x7F, 0x81, 0x01,
+ 0x81, 0x25, 0x22, 0x01, 0x07, 0x12, 0x01, 0x00, 0x31, 0x0E, 0x06, 0x0A,
+ 0x21, 0x01, 0x10, 0x12, 0x06, 0x02, 0x81, 0x1C, 0x04, 0x24, 0x01, 0x01,
+ 0x31, 0x0E, 0x06, 0x1B, 0x21, 0x21, 0x6B, 0x27, 0x01, 0x01, 0x0D, 0x06,
+ 0x06, 0x01, 0x00, 0x81, 0x01, 0x04, 0x0A, 0x24, 0x16, 0x2F, 0x06, 0x05,
+ 0x81, 0x25, 0x21, 0x04, 0x77, 0x04, 0x03, 0x56, 0x23, 0x21, 0x04, 0x44,
+ 0x01, 0x22, 0x03, 0x00, 0x09, 0x22, 0x44, 0x06, 0x02, 0x50, 0x23, 0x02,
+ 0x00, 0x00, 0x00, 0x7C, 0x01, 0x0F, 0x12, 0x00, 0x00, 0x58, 0x27, 0x01,
+ 0x00, 0x31, 0x0E, 0x06, 0x10, 0x21, 0x22, 0x01, 0x01, 0x0D, 0x06, 0x03,
+ 0x21, 0x01, 0x02, 0x58, 0x38, 0x01, 0x00, 0x04, 0x15, 0x01, 0x01, 0x31,
+ 0x0E, 0x06, 0x09, 0x21, 0x01, 0x00, 0x58, 0x38, 0x46, 0x00, 0x04, 0x06,
+ 0x01, 0x82, 0x00, 0x08, 0x23, 0x21, 0x00, 0x00, 0x01, 0x00, 0x28, 0x06,
+ 0x06, 0x33, 0x81, 0x08, 0x30, 0x04, 0x77, 0x22, 0x06, 0x04, 0x01, 0x01,
+ 0x71, 0x38, 0x00, 0x00, 0x28, 0x06, 0x0B, 0x69, 0x27, 0x01, 0x14, 0x0D,
+ 0x06, 0x02, 0x56, 0x23, 0x04, 0x12, 0x81, 0x25, 0x01, 0x07, 0x12, 0x22,
+ 0x01, 0x02, 0x0D, 0x06, 0x06, 0x06, 0x02, 0x56, 0x23, 0x04, 0x6F, 0x21,
+ 0x81, 0x1A, 0x01, 0x01, 0x0D, 0x2C, 0x30, 0x06, 0x02, 0x4C, 0x23, 0x22,
+ 0x01, 0x01, 0x81, 0x20, 0x2F, 0x81, 0x0D, 0x00, 0x0A, 0x81, 0x12, 0x01,
+ 0x01, 0x0E, 0x05, 0x02, 0x56, 0x23, 0x81, 0x17, 0x22, 0x03, 0x00, 0x5B,
+ 0x36, 0x5C, 0x01, 0x20, 0x81, 0x0E, 0x81, 0x19, 0x22, 0x01, 0x20, 0x0F,
+ 0x06, 0x02, 0x55, 0x23, 0x22, 0x70, 0x38, 0x6F, 0x3B, 0x81, 0x0E, 0x17,
+ 0x03, 0x01, 0x81, 0x17, 0x81, 0x06, 0x01, 0x00, 0x03, 0x02, 0x01, 0x00,
+ 0x03, 0x03, 0x65, 0x81, 0x02, 0x14, 0x31, 0x08, 0x03, 0x04, 0x03, 0x05,
+ 0x22, 0x06, 0x80, 0x57, 0x81, 0x17, 0x22, 0x03, 0x06, 0x02, 0x01, 0x06,
+ 0x0A, 0x22, 0x5A, 0x25, 0x0E, 0x06, 0x04, 0x01, 0x7F, 0x03, 0x03, 0x22,
+ 0x01, 0x81, 0x7F, 0x0E, 0x06, 0x0A, 0x6B, 0x27, 0x06, 0x02, 0x51, 0x23,
+ 0x01, 0x7F, 0x03, 0x02, 0x81, 0x1B, 0x22, 0x44, 0x06, 0x03, 0x21, 0x04,
+ 0x27, 0x01, 0x00, 0x81, 0x04, 0x06, 0x0B, 0x01, 0x02, 0x0B, 0x5D, 0x08,
+ 0x02, 0x06, 0x3B, 0x36, 0x04, 0x16, 0x21, 0x02, 0x05, 0x02, 0x04, 0x10,
+ 0x06, 0x02, 0x4F, 0x23, 0x02, 0x06, 0x02, 0x05, 0x36, 0x02, 0x05, 0x01,
+ 0x04, 0x08, 0x03, 0x05, 0x04, 0xFF, 0x25, 0x21, 0x01, 0x00, 0x03, 0x07,
+ 0x81, 0x19, 0x81, 0x06, 0x22, 0x06, 0x0A, 0x81, 0x19, 0x05, 0x04, 0x01,
+ 0x7F, 0x03, 0x07, 0x04, 0x73, 0x7D, 0x01, 0x00, 0x6D, 0x38, 0x01, 0x88,
+ 0x04, 0x64, 0x36, 0x01, 0x84, 0x80, 0x80, 0x00, 0x60, 0x37, 0x22, 0x06,
+ 0x80, 0x58, 0x81, 0x17, 0x81, 0x06, 0x22, 0x06, 0x80, 0x4F, 0x81, 0x17,
+ 0x01, 0x00, 0x31, 0x0E, 0x06, 0x05, 0x21, 0x81, 0x11, 0x04, 0x3F, 0x01,
+ 0x01, 0x31, 0x0E, 0x06, 0x05, 0x21, 0x81, 0x0F, 0x04, 0x34, 0x01, 0x83,
+ 0xFE, 0x01, 0x31, 0x0E, 0x06, 0x05, 0x21, 0x81, 0x10, 0x04, 0x27, 0x01,
+ 0x0D, 0x31, 0x0E, 0x06, 0x05, 0x21, 0x81, 0x15, 0x04, 0x1C, 0x01, 0x0A,
+ 0x31, 0x0E, 0x06, 0x05, 0x21, 0x81, 0x16, 0x04, 0x11, 0x01, 0x0B, 0x31,
+ 0x0E, 0x06, 0x05, 0x21, 0x81, 0x14, 0x04, 0x06, 0x21, 0x81, 0x14, 0x01,
+ 0x00, 0x21, 0x04, 0xFF, 0x2D, 0x7D, 0x7D, 0x02, 0x01, 0x02, 0x03, 0x12,
+ 0x03, 0x01, 0x77, 0x25, 0x22, 0x02, 0x00, 0x0F, 0x06, 0x03, 0x21, 0x02,
+ 0x00, 0x22, 0x01, 0x86, 0x00, 0x0A, 0x06, 0x02, 0x52, 0x23, 0x02, 0x00,
+ 0x78, 0x25, 0x0A, 0x06, 0x05, 0x01, 0x80, 0x46, 0x81, 0x03, 0x02, 0x01,
+ 0x06, 0x10, 0x75, 0x25, 0x02, 0x00, 0x0C, 0x06, 0x05, 0x21, 0x75, 0x25,
+ 0x04, 0x04, 0x01, 0x00, 0x03, 0x01, 0x22, 0x75, 0x36, 0x22, 0x76, 0x36,
+ 0x22, 0x79, 0x36, 0x01, 0x86, 0x03, 0x10, 0x03, 0x08, 0x02, 0x02, 0x06,
+ 0x04, 0x01, 0x02, 0x6B, 0x38, 0x02, 0x07, 0x05, 0x04, 0x01, 0x28, 0x81,
+ 0x03, 0x3A, 0x21, 0x01, 0x82, 0x01, 0x07, 0x64, 0x25, 0x12, 0x22, 0x64,
+ 0x36, 0x45, 0x03, 0x09, 0x60, 0x26, 0x39, 0x12, 0x22, 0x60, 0x37, 0x05,
+ 0x04, 0x01, 0x00, 0x03, 0x09, 0x02, 0x01, 0x06, 0x03, 0x01, 0x7F, 0x00,
+ 0x6F, 0x01, 0x20, 0x2B, 0x5D, 0x22, 0x03, 0x05, 0x22, 0x02, 0x04, 0x0A,
+ 0x06, 0x80, 0x47, 0x22, 0x25, 0x22, 0x7C, 0x02, 0x09, 0x05, 0x13, 0x22,
+ 0x01, 0x0C, 0x11, 0x22, 0x01, 0x01, 0x0E, 0x3B, 0x01, 0x02, 0x0E, 0x30,
+ 0x06, 0x04, 0x4B, 0x01, 0x00, 0x22, 0x02, 0x08, 0x05, 0x0E, 0x22, 0x01,
+ 0x81, 0x70, 0x12, 0x01, 0x20, 0x0D, 0x06, 0x04, 0x4B, 0x01, 0x00, 0x22,
+ 0x22, 0x06, 0x10, 0x02, 0x05, 0x4A, 0x36, 0x02, 0x05, 0x36, 0x02, 0x05,
+ 0x01, 0x04, 0x08, 0x03, 0x05, 0x04, 0x01, 0x4B, 0x01, 0x04, 0x08, 0x04,
+ 0xFF, 0x32, 0x21, 0x02, 0x05, 0x5D, 0x09, 0x01, 0x02, 0x11, 0x22, 0x05,
+ 0x04, 0x01, 0x28, 0x81, 0x03, 0x5E, 0x38, 0x15, 0x05, 0x04, 0x01, 0x28,
+ 0x81, 0x03, 0x01, 0x00, 0x00, 0x04, 0x81, 0x12, 0x01, 0x10, 0x0E, 0x05,
+ 0x02, 0x56, 0x23, 0x5A, 0x25, 0x81, 0x24, 0x06, 0x19, 0x81, 0x17, 0x22,
+ 0x01, 0x84, 0x00, 0x0F, 0x06, 0x02, 0x53, 0x23, 0x22, 0x03, 0x00, 0x67,
+ 0x3B, 0x81, 0x0E, 0x02, 0x00, 0x5A, 0x25, 0x81, 0x07, 0x20, 0x5A, 0x25,
+ 0x22, 0x81, 0x22, 0x3B, 0x81, 0x21, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01,
+ 0x02, 0x02, 0x30, 0x06, 0x17, 0x81, 0x19, 0x22, 0x03, 0x03, 0x67, 0x3B,
+ 0x81, 0x0E, 0x02, 0x03, 0x5A, 0x25, 0x81, 0x07, 0x02, 0x02, 0x06, 0x03,
+ 0x1F, 0x04, 0x01, 0x1D, 0x7D, 0x00, 0x00, 0x7E, 0x81, 0x12, 0x01, 0x14,
+ 0x0D, 0x06, 0x02, 0x56, 0x23, 0x67, 0x01, 0x0C, 0x08, 0x01, 0x0C, 0x81,
+ 0x0E, 0x7D, 0x67, 0x22, 0x01, 0x0C, 0x08, 0x01, 0x0C, 0x29, 0x05, 0x02,
+ 0x4D, 0x23, 0x00, 0x02, 0x03, 0x00, 0x03, 0x01, 0x02, 0x00, 0x7A, 0x02,
+ 0x01, 0x02, 0x00, 0x32, 0x22, 0x01, 0x00, 0x0E, 0x06, 0x02, 0x4B, 0x00,
+ 0x81, 0x27, 0x04, 0x73, 0x00, 0x81, 0x17, 0x01, 0x01, 0x0D, 0x06, 0x02,
+ 0x4E, 0x23, 0x81, 0x19, 0x22, 0x22, 0x46, 0x3B, 0x01, 0x05, 0x10, 0x30,
+ 0x06, 0x02, 0x4E, 0x23, 0x01, 0x08, 0x08, 0x22, 0x66, 0x27, 0x0A, 0x06,
+ 0x0D, 0x22, 0x01, 0x01, 0x3B, 0x0B, 0x35, 0x22, 0x66, 0x38, 0x68, 0x38,
+ 0x04, 0x01, 0x21, 0x00, 0x00, 0x81, 0x17, 0x6B, 0x27, 0x01, 0x00, 0x31,
+ 0x0E, 0x06, 0x14, 0x21, 0x01, 0x01, 0x0E, 0x05, 0x02, 0x51, 0x23, 0x81,
+ 0x19, 0x06, 0x02, 0x51, 0x23, 0x01, 0x02, 0x6B, 0x38, 0x04, 0x2A, 0x01,
+ 0x02, 0x31, 0x0E, 0x06, 0x21, 0x21, 0x01, 0x0D, 0x0E, 0x05, 0x02, 0x51,
+ 0x23, 0x81, 0x19, 0x01, 0x0C, 0x0E, 0x05, 0x02, 0x51, 0x23, 0x67, 0x01,
+ 0x0C, 0x81, 0x0E, 0x6C, 0x67, 0x01, 0x0C, 0x29, 0x05, 0x02, 0x51, 0x23,
+ 0x04, 0x03, 0x51, 0x23, 0x21, 0x00, 0x00, 0x81, 0x17, 0x81, 0x06, 0x81,
+ 0x17, 0x81, 0x06, 0x22, 0x06, 0x22, 0x81, 0x19, 0x06, 0x04, 0x81, 0x14,
+ 0x04, 0x18, 0x81, 0x17, 0x22, 0x01, 0x81, 0x7F, 0x0C, 0x06, 0x0D, 0x22,
+ 0x6D, 0x08, 0x01, 0x00, 0x3B, 0x38, 0x6D, 0x3B, 0x81, 0x0E, 0x04, 0x02,
+ 0x81, 0x1F, 0x04, 0x5B, 0x7D, 0x7D, 0x00, 0x00, 0x81, 0x13, 0x22, 0x46,
+ 0x06, 0x07, 0x21, 0x06, 0x02, 0x4F, 0x23, 0x04, 0x73, 0x00, 0x00, 0x81,
+ 0x1A, 0x01, 0x03, 0x81, 0x18, 0x3B, 0x21, 0x3B, 0x00, 0x00, 0x81, 0x17,
+ 0x81, 0x1F, 0x00, 0x02, 0x81, 0x17, 0x81, 0x06, 0x01, 0x00, 0x64, 0x36,
+ 0x81, 0x17, 0x81, 0x06, 0x22, 0x06, 0x34, 0x81, 0x19, 0x03, 0x00, 0x81,
+ 0x19, 0x03, 0x01, 0x02, 0x00, 0x01, 0x02, 0x10, 0x02, 0x00, 0x01, 0x06,
+ 0x0C, 0x12, 0x02, 0x01, 0x01, 0x01, 0x0E, 0x02, 0x01, 0x01, 0x03, 0x0E,
+ 0x30, 0x12, 0x06, 0x11, 0x64, 0x25, 0x01, 0x01, 0x02, 0x01, 0x49, 0x01,
+ 0x02, 0x0B, 0x02, 0x00, 0x08, 0x0B, 0x30, 0x64, 0x36, 0x04, 0x49, 0x7D,
+ 0x7D, 0x00, 0x00, 0x81, 0x17, 0x81, 0x06, 0x81, 0x17, 0x81, 0x06, 0x01,
+ 0x00, 0x60, 0x37, 0x22, 0x06, 0x16, 0x81, 0x17, 0x22, 0x01, 0x20, 0x0A,
+ 0x06, 0x0B, 0x01, 0x01, 0x3B, 0x0B, 0x60, 0x26, 0x30, 0x60, 0x37, 0x04,
+ 0x01, 0x21, 0x04, 0x67, 0x7D, 0x7D, 0x00, 0x00, 0x01, 0x02, 0x7A, 0x81,
+ 0x1A, 0x01, 0x08, 0x0B, 0x81, 0x1A, 0x08, 0x00, 0x00, 0x01, 0x03, 0x7A,
+ 0x81, 0x1A, 0x01, 0x08, 0x0B, 0x81, 0x1A, 0x08, 0x01, 0x08, 0x0B, 0x81,
+ 0x1A, 0x08, 0x00, 0x00, 0x01, 0x01, 0x7A, 0x81, 0x1A, 0x00, 0x00, 0x33,
+ 0x22, 0x44, 0x05, 0x01, 0x00, 0x21, 0x81, 0x27, 0x04, 0x75, 0x02, 0x03,
+ 0x00, 0x74, 0x27, 0x03, 0x01, 0x01, 0x00, 0x22, 0x02, 0x01, 0x0A, 0x06,
+ 0x10, 0x22, 0x01, 0x01, 0x0B, 0x73, 0x08, 0x25, 0x02, 0x00, 0x0E, 0x06,
+ 0x01, 0x00, 0x48, 0x04, 0x6A, 0x21, 0x01, 0x7F, 0x00, 0x00, 0x24, 0x16,
+ 0x2F, 0x06, 0x05, 0x81, 0x25, 0x21, 0x04, 0x77, 0x01, 0x16, 0x6A, 0x38,
+ 0x01, 0x00, 0x81, 0x33, 0x01, 0x00, 0x81, 0x32, 0x24, 0x01, 0x17, 0x6A,
+ 0x38, 0x00, 0x00, 0x01, 0x15, 0x6A, 0x38, 0x3B, 0x43, 0x21, 0x43, 0x21,
+ 0x24, 0x00, 0x00, 0x01, 0x01, 0x3B, 0x81, 0x1D, 0x00, 0x00, 0x3B, 0x31,
+ 0x7A, 0x3B, 0x22, 0x06, 0x06, 0x81, 0x1A, 0x21, 0x49, 0x04, 0x77, 0x21,
+ 0x00, 0x02, 0x03, 0x00, 0x5A, 0x25, 0x7C, 0x03, 0x01, 0x02, 0x01, 0x01,
+ 0x0F, 0x12, 0x02, 0x01, 0x01, 0x04, 0x11, 0x01, 0x0F, 0x12, 0x02, 0x01,
+ 0x01, 0x08, 0x11, 0x01, 0x0F, 0x12, 0x01, 0x00, 0x31, 0x0E, 0x06, 0x10,
+ 0x21, 0x01, 0x00, 0x01, 0x18, 0x02, 0x00, 0x06, 0x03, 0x3E, 0x04, 0x01,
+ 0x3F, 0x04, 0x80, 0x56, 0x01, 0x01, 0x31, 0x0E, 0x06, 0x10, 0x21, 0x01,
+ 0x01, 0x01, 0x10, 0x02, 0x00, 0x06, 0x03, 0x3E, 0x04, 0x01, 0x3F, 0x04,
+ 0x80, 0x40, 0x01, 0x02, 0x31, 0x0E, 0x06, 0x0F, 0x21, 0x01, 0x01, 0x01,
+ 0x20, 0x02, 0x00, 0x06, 0x03, 0x3E, 0x04, 0x01, 0x3F, 0x04, 0x2B, 0x01,
+ 0x03, 0x31, 0x0E, 0x06, 0x0E, 0x21, 0x21, 0x01, 0x10, 0x02, 0x00, 0x06,
+ 0x03, 0x3C, 0x04, 0x01, 0x3D, 0x04, 0x17, 0x01, 0x04, 0x31, 0x0E, 0x06,
+ 0x0E, 0x21, 0x21, 0x01, 0x20, 0x02, 0x00, 0x06, 0x03, 0x3C, 0x04, 0x01,
+ 0x3D, 0x04, 0x03, 0x50, 0x23, 0x21, 0x00, 0x00, 0x7C, 0x01, 0x0C, 0x11,
+ 0x01, 0x02, 0x0F, 0x00, 0x00, 0x7C, 0x01, 0x0C, 0x11, 0x22, 0x47, 0x3B,
+ 0x01, 0x03, 0x0A, 0x12, 0x00, 0x00, 0x7C, 0x01, 0x0C, 0x11, 0x01, 0x01,
+ 0x0E, 0x00, 0x00, 0x7C, 0x01, 0x0C, 0x11, 0x46, 0x00, 0x00, 0x18, 0x01,
+ 0x00, 0x57, 0x27, 0x22, 0x06, 0x20, 0x01, 0x01, 0x31, 0x0E, 0x06, 0x07,
+ 0x21, 0x01, 0x00, 0x81, 0x00, 0x04, 0x11, 0x01, 0x02, 0x31, 0x0E, 0x06,
+ 0x0A, 0x21, 0x59, 0x27, 0x06, 0x03, 0x01, 0x10, 0x30, 0x04, 0x01, 0x21,
+ 0x04, 0x01, 0x21, 0x5F, 0x27, 0x05, 0x35, 0x28, 0x06, 0x32, 0x69, 0x27,
+ 0x01, 0x14, 0x31, 0x0E, 0x06, 0x06, 0x21, 0x01, 0x02, 0x30, 0x04, 0x24,
+ 0x01, 0x15, 0x31, 0x0E, 0x06, 0x0B, 0x21, 0x81, 0x09, 0x06, 0x04, 0x01,
+ 0x7F, 0x81, 0x00, 0x04, 0x13, 0x01, 0x16, 0x31, 0x0E, 0x06, 0x06, 0x21,
+ 0x01, 0x01, 0x30, 0x04, 0x07, 0x21, 0x01, 0x04, 0x30, 0x01, 0x00, 0x21,
+ 0x16, 0x06, 0x03, 0x01, 0x08, 0x30, 0x00, 0x00, 0x18, 0x22, 0x05, 0x10,
+ 0x28, 0x06, 0x0D, 0x69, 0x27, 0x01, 0x15, 0x0E, 0x06, 0x05, 0x21, 0x81,
+ 0x09, 0x04, 0x01, 0x1C, 0x00, 0x00, 0x81, 0x25, 0x01, 0x07, 0x12, 0x01,
+ 0x01, 0x0F, 0x06, 0x02, 0x56, 0x23, 0x00, 0x01, 0x03, 0x00, 0x24, 0x16,
+ 0x06, 0x05, 0x02, 0x00, 0x6A, 0x38, 0x00, 0x81, 0x25, 0x21, 0x04, 0x73,
+ 0x00, 0x01, 0x14, 0x81, 0x28, 0x01, 0x01, 0x81, 0x33, 0x24, 0x22, 0x01,
+ 0x00, 0x81, 0x20, 0x01, 0x16, 0x81, 0x28, 0x81, 0x2B, 0x24, 0x00, 0x00,
+ 0x01, 0x0B, 0x81, 0x33, 0x40, 0x22, 0x01, 0x03, 0x08, 0x81, 0x32, 0x81,
+ 0x32, 0x13, 0x22, 0x44, 0x06, 0x02, 0x21, 0x00, 0x81, 0x32, 0x1A, 0x22,
+ 0x06, 0x06, 0x67, 0x3B, 0x81, 0x2F, 0x04, 0x76, 0x21, 0x04, 0x6A, 0x00,
+ 0x7E, 0x01, 0x14, 0x81, 0x33, 0x01, 0x0C, 0x81, 0x32, 0x67, 0x01, 0x0C,
+ 0x81, 0x2F, 0x00, 0x03, 0x03, 0x00, 0x01, 0x02, 0x81, 0x33, 0x01, 0x80,
+ 0x46, 0x6B, 0x27, 0x01, 0x02, 0x0E, 0x06, 0x0C, 0x02, 0x00, 0x06, 0x04,
+ 0x01, 0x05, 0x04, 0x02, 0x01, 0x1D, 0x04, 0x02, 0x01, 0x00, 0x03, 0x01,
+ 0x68, 0x27, 0x06, 0x04, 0x01, 0x05, 0x04, 0x02, 0x01, 0x00, 0x03, 0x02,
+ 0x02, 0x01, 0x02, 0x02, 0x08, 0x22, 0x06, 0x03, 0x01, 0x02, 0x08, 0x08,
+ 0x81, 0x32, 0x75, 0x25, 0x81, 0x31, 0x6E, 0x01, 0x04, 0x14, 0x6E, 0x01,
+ 0x04, 0x08, 0x01, 0x1C, 0x2B, 0x6E, 0x01, 0x20, 0x81, 0x2F, 0x01, 0x20,
+ 0x81, 0x33, 0x6F, 0x01, 0x20, 0x81, 0x2F, 0x5A, 0x25, 0x81, 0x31, 0x01,
+ 0x00, 0x81, 0x33, 0x02, 0x01, 0x02, 0x02, 0x08, 0x22, 0x06, 0x30, 0x81,
+ 0x31, 0x02, 0x01, 0x22, 0x06, 0x13, 0x01, 0x83, 0xFE, 0x01, 0x81, 0x31,
+ 0x01, 0x04, 0x09, 0x22, 0x81, 0x31, 0x49, 0x6C, 0x3B, 0x81, 0x30, 0x04,
+ 0x01, 0x21, 0x02, 0x02, 0x06, 0x0F, 0x01, 0x01, 0x81, 0x31, 0x01, 0x01,
+ 0x81, 0x31, 0x68, 0x27, 0x01, 0x08, 0x09, 0x81, 0x33, 0x04, 0x01, 0x21,
+ 0x00, 0x00, 0x01, 0x0E, 0x81, 0x33, 0x01, 0x00, 0x81, 0x32, 0x00, 0x03,
+ 0x5A, 0x25, 0x81, 0x22, 0x05, 0x01, 0x00, 0x60, 0x26, 0x01, 0x00, 0x81,
+ 0x02, 0x11, 0x01, 0x01, 0x12, 0x46, 0x06, 0x03, 0x48, 0x04, 0x74, 0x03,
+ 0x00, 0x21, 0x02, 0x00, 0x1E, 0x22, 0x44, 0x06, 0x02, 0x2E, 0x23, 0x03,
+ 0x01, 0x75, 0x25, 0x01, 0x86, 0x03, 0x10, 0x03, 0x02, 0x01, 0x0C, 0x81,
+ 0x33, 0x02, 0x01, 0x62, 0x27, 0x08, 0x02, 0x02, 0x01, 0x02, 0x12, 0x08,
+ 0x01, 0x06, 0x08, 0x81, 0x32, 0x01, 0x03, 0x81, 0x33, 0x02, 0x00, 0x81,
+ 0x31, 0x61, 0x62, 0x27, 0x81, 0x30, 0x02, 0x02, 0x06, 0x10, 0x72, 0x27,
+ 0x81, 0x33, 0x5A, 0x25, 0x81, 0x23, 0x01, 0x01, 0x0B, 0x01, 0x03, 0x08,
+ 0x81, 0x33, 0x02, 0x01, 0x81, 0x31, 0x67, 0x02, 0x01, 0x81, 0x2F, 0x00,
+ 0x00, 0x42, 0x22, 0x01, 0x00, 0x0E, 0x06, 0x02, 0x4B, 0x00, 0x81, 0x25,
+ 0x21, 0x04, 0x72, 0x00, 0x22, 0x81, 0x33, 0x81, 0x2F, 0x00, 0x00, 0x22,
+ 0x01, 0x08, 0x41, 0x81, 0x33, 0x81, 0x33, 0x00, 0x00, 0x22, 0x01, 0x10,
+ 0x41, 0x81, 0x33, 0x81, 0x31, 0x00, 0x00, 0x22, 0x43, 0x06, 0x02, 0x21,
+ 0x00, 0x81, 0x25, 0x21, 0x04, 0x75
+};
+
+static const uint16_t t0_caddr[] = {
+ 0,
+ 5,
+ 10,
+ 15,
+ 20,
+ 25,
+ 30,
+ 35,
+ 39,
+ 43,
+ 47,
+ 51,
+ 55,
+ 59,
+ 63,
+ 67,
+ 71,
+ 75,
+ 79,
+ 83,
+ 88,
+ 93,
+ 98,
+ 103,
+ 108,
+ 113,
+ 118,
+ 123,
+ 128,
+ 133,
+ 138,
+ 143,
+ 148,
+ 153,
+ 159,
+ 164,
+ 169,
+ 174,
+ 179,
+ 184,
+ 189,
+ 194,
+ 199,
+ 204,
+ 209,
+ 214,
+ 219,
+ 224,
+ 229,
+ 234,
+ 239,
+ 244,
+ 249,
+ 254,
+ 259,
+ 268,
+ 272,
+ 297,
+ 303,
+ 323,
+ 334,
+ 371,
+ 431,
+ 435,
+ 471,
+ 481,
+ 546,
+ 560,
+ 566,
+ 613,
+ 633,
+ 686,
+ 1211,
+ 1296,
+ 1329,
+ 1354,
+ 1402,
+ 1476,
+ 1525,
+ 1540,
+ 1551,
+ 1557,
+ 1628,
+ 1669,
+ 1682,
+ 1701,
+ 1708,
+ 1720,
+ 1755,
+ 1784,
+ 1796,
+ 1803,
+ 1819,
+ 1957,
+ 1966,
+ 1979,
+ 1988,
+ 1995,
+ 2101,
+ 2123,
+ 2137,
+ 2154,
+ 2177,
+ 2213,
+ 2229,
+ 2383,
+ 2393,
+ 2502,
+ 2517,
+ 2524,
+ 2534,
+ 2544
+};
+
+#define T0_INTERPRETED 68
+
+#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_ssl_hs_server_init_main, 133)
+
+void
+br_ssl_hs_server_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() break
+
+ dp = ((t0_context *)t0ctx)->dp;
+ rp = ((t0_context *)t0ctx)->rp;
+ ip = ((t0_context *)t0ctx)->ip;
+ for (;;) {
+ uint32_t t0x;
+
+ t0x = t0_parse7E_unsigned(&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: {
+ /* - */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a - b);
+
+ }
+ 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: {
+ /* <= */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ 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: {
+ /* = */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ 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: {
+ /* >= */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a >= b));
+
+ }
+ break;
+ case 17: {
+ /* >> */
+
+ int c = (int)T0_POPi();
+ int32_t x = T0_POPi();
+ T0_PUSHi(x >> c);
+
+ }
+ break;
+ case 18: {
+ /* and */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a & b);
+
+ }
+ break;
+ case 19: {
+ /* begin-cert */
+
+ if (CTX->chain_len == 0) {
+ T0_PUSHi(-1);
+ } else {
+ CTX->cert_cur = CTX->chain->data;
+ CTX->cert_len = CTX->chain->data_len;
+ CTX->chain ++;
+ CTX->chain_len --;
+ T0_PUSH(CTX->cert_len);
+ }
+
+ }
+ break;
+ case 20: {
+ /* bzero */
+
+ size_t len = (size_t)T0_POP();
+ void *addr = (unsigned char *)ENG + (size_t)T0_POP();
+ memset(addr, 0, len);
+
+ }
+ break;
+ case 21: {
+ /* call-policy-handler */
+
+ int x;
+ br_ssl_server_choices choices;
+
+ x = (*CTX->policy_vtable)->choose(
+ CTX->policy_vtable, CTX, &choices);
+ ENG->session.cipher_suite = choices.cipher_suite;
+ CTX->sign_hash_id = choices.hash_id;
+ CTX->chain = choices.chain;
+ CTX->chain_len = choices.chain_len;
+ T0_PUSHi(-(x != 0));
+
+ }
+ break;
+ case 22: {
+ /* can-output? */
+
+ T0_PUSHi(-(ENG->hlen_out > 0));
+
+ }
+ break;
+ case 23: {
+ /* check-resume */
+
+ if (ENG->session.session_id_len == 32
+ && CTX->cache_vtable != NULL && (*CTX->cache_vtable)->load(
+ CTX->cache_vtable, CTX, &ENG->session))
+ {
+ T0_PUSHi(-1);
+ } else {
+ T0_PUSH(0);
+ }
+
+ }
+ break;
+ case 24: {
+ /* co */
+ T0_CO();
+ }
+ break;
+ case 25: {
+ /* compute-Finished-inner */
+
+ int prf_id = T0_POP();
+ int from_client = T0_POPi();
+ unsigned char seed[48];
+ size_t seed_len;
+
+ br_tls_prf_impl prf = br_ssl_engine_get_PRF(ENG, prf_id);
+ if (ENG->session.version >= BR_TLS12) {
+ seed_len = br_multihash_out(&ENG->mhash, prf_id, seed);
+ } else {
+ br_multihash_out(&ENG->mhash, br_md5_ID, seed);
+ br_multihash_out(&ENG->mhash, br_sha1_ID, seed + 16);
+ seed_len = 36;
+ }
+ prf(ENG->pad, 12, ENG->session.master_secret,
+ sizeof ENG->session.master_secret,
+ from_client ? "client finished" : "server finished",
+ seed, seed_len);
+
+ }
+ break;
+ case 26: {
+ /* copy-cert-chunk */
+
+ size_t clen;
+
+ clen = CTX->cert_len;
+ if (clen > sizeof ENG->pad) {
+ clen = sizeof ENG->pad;
+ }
+ memcpy(ENG->pad, CTX->cert_cur, clen);
+ CTX->cert_cur += clen;
+ CTX->cert_len -= clen;
+ T0_PUSH(clen);
+
+ }
+ break;
+ case 27: {
+ /* data-get8 */
+
+ size_t addr = T0_POP();
+ T0_PUSH(t0_datablock[addr]);
+
+ }
+ break;
+ case 28: {
+ /* discard-input */
+
+ ENG->hlen_in = 0;
+
+ }
+ break;
+ case 29: {
+ /* do-ecdh */
+
+ int prf_id = T0_POPi();
+ size_t len = T0_POP();
+ do_ecdh(CTX, prf_id, ENG->pad, len);
+
+ }
+ break;
+ case 30: {
+ /* do-ecdhe-part1 */
+
+ int curve = T0_POPi();
+ T0_PUSHi(do_ecdhe_part1(CTX, curve));
+
+ }
+ break;
+ case 31: {
+ /* do-ecdhe-part2 */
+
+ int prf_id = T0_POPi();
+ size_t len = T0_POP();
+ do_ecdhe_part2(CTX, prf_id, ENG->pad, len);
+
+ }
+ break;
+ case 32: {
+ /* do-rsa-decrypt */
+
+ int prf_id = T0_POPi();
+ size_t len = T0_POP();
+ do_rsa_decrypt(CTX, prf_id, ENG->pad, len);
+
+ }
+ break;
+ case 33: {
+ /* drop */
+ (void)T0_POP();
+ }
+ break;
+ case 34: {
+ /* dup */
+ T0_PUSH(T0_PEEK(0));
+ }
+ break;
+ case 35: {
+ /* fail */
+
+ br_ssl_engine_fail(ENG, (int)T0_POPi());
+ T0_CO();
+
+ }
+ break;
+ case 36: {
+ /* flush-record */
+
+ br_ssl_engine_flush_record(ENG);
+
+ }
+ break;
+ case 37: {
+ /* get16 */
+
+ size_t addr = (size_t)T0_POP();
+ T0_PUSH(*(uint16_t *)((unsigned char *)ENG + addr));
+
+ }
+ break;
+ case 38: {
+ /* get32 */
+
+ size_t addr = (size_t)T0_POP();
+ T0_PUSH(*(uint32_t *)((unsigned char *)ENG + addr));
+
+ }
+ break;
+ case 39: {
+ /* get8 */
+
+ size_t addr = (size_t)T0_POP();
+ T0_PUSH(*((unsigned char *)ENG + addr));
+
+ }
+ break;
+ case 40: {
+ /* has-input? */
+
+ T0_PUSHi(-(ENG->hlen_in != 0));
+
+ }
+ break;
+ case 41: {
+ /* memcmp */
+
+ size_t len = (size_t)T0_POP();
+ void *addr2 = (unsigned char *)ENG + (size_t)T0_POP();
+ void *addr1 = (unsigned char *)ENG + (size_t)T0_POP();
+ int x = memcmp(addr1, addr2, len);
+ T0_PUSH((uint32_t)-(x == 0));
+
+ }
+ break;
+ case 42: {
+ /* memcpy */
+
+ size_t len = (size_t)T0_POP();
+ void *src = (unsigned char *)ENG + (size_t)T0_POP();
+ void *dst = (unsigned char *)ENG + (size_t)T0_POP();
+ memcpy(dst, src, len);
+
+ }
+ break;
+ case 43: {
+ /* mkrand */
+
+ size_t len = (size_t)T0_POP();
+ void *addr = (unsigned char *)ENG + (size_t)T0_POP();
+ br_hmac_drbg_generate(&ENG->rng, addr, len);
+
+ }
+ break;
+ case 44: {
+ /* more-incoming-bytes? */
+
+ T0_PUSHi(ENG->hlen_in != 0 || !br_ssl_engine_recvrec_finished(ENG));
+
+ }
+ break;
+ case 45: {
+ /* multihash-init */
+
+ br_multihash_init(&ENG->mhash);
+
+ }
+ break;
+ case 46: {
+ /* neg */
+
+ uint32_t a = T0_POP();
+ T0_PUSH(-a);
+
+ }
+ break;
+ case 47: {
+ /* not */
+
+ uint32_t a = T0_POP();
+ T0_PUSH(~a);
+
+ }
+ break;
+ case 48: {
+ /* or */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a | b);
+
+ }
+ break;
+ case 49: {
+ /* over */
+ T0_PUSH(T0_PEEK(1));
+ }
+ break;
+ case 50: {
+ /* read-chunk-native */
+
+ size_t clen = ENG->hlen_in;
+ if (clen > 0) {
+ uint32_t addr, len;
+
+ len = T0_POP();
+ addr = T0_POP();
+ if ((size_t)len < clen) {
+ clen = (size_t)len;
+ }
+ memcpy((unsigned char *)ENG + addr, ENG->hbuf_in, clen);
+ if (ENG->record_type_in == BR_SSL_HANDSHAKE) {
+ br_multihash_update(&ENG->mhash, ENG->hbuf_in, clen);
+ }
+ T0_PUSH(addr + (uint32_t)clen);
+ T0_PUSH(len - (uint32_t)clen);
+ ENG->hbuf_in += clen;
+ ENG->hlen_in -= clen;
+ }
+
+ }
+ break;
+ case 51: {
+ /* read8-native */
+
+ if (ENG->hlen_in > 0) {
+ unsigned char x;
+
+ x = *ENG->hbuf_in ++;
+ if (ENG->record_type_in == BR_SSL_HANDSHAKE) {
+ br_multihash_update(&ENG->mhash, &x, 1);
+ }
+ T0_PUSH(x);
+ ENG->hlen_in --;
+ } else {
+ T0_PUSHi(-1);
+ }
+
+ }
+ break;
+ case 52: {
+ /* save-session */
+
+ if (CTX->cache_vtable != NULL) {
+ (*CTX->cache_vtable)->save(
+ CTX->cache_vtable, CTX, &ENG->session);
+ }
+
+ }
+ break;
+ case 53: {
+ /* set-max-frag-len */
+
+ size_t max_frag_len = T0_POP();
+
+ br_ssl_engine_new_max_frag_len(ENG, max_frag_len);
+
+ /*
+ * We must adjust our own output limit. Since we call this only
+ * after receiving a ClientHello and before beginning to send
+ * the ServerHello, the next output record should be empty at
+ * that point, so we can use max_frag_len as a limit.
+ */
+ if (ENG->hlen_out > max_frag_len) {
+ ENG->hlen_out = max_frag_len;
+ }
+
+ }
+ break;
+ case 54: {
+ /* set16 */
+
+ size_t addr = (size_t)T0_POP();
+ *(uint16_t *)((unsigned char *)ENG + addr) = (uint16_t)T0_POP();
+
+ }
+ break;
+ case 55: {
+ /* set32 */
+
+ size_t addr = (size_t)T0_POP();
+ *(uint32_t *)((unsigned char *)ENG + addr) = (uint32_t)T0_POP();
+
+ }
+ break;
+ case 56: {
+ /* set8 */
+
+ size_t addr = (size_t)T0_POP();
+ *((unsigned char *)ENG + addr) = (unsigned char)T0_POP();
+
+ }
+ break;
+ case 57: {
+ /* supported-curves */
+
+ uint32_t x = ENG->iec == NULL ? 0 : ENG->iec->supported_curves;
+ T0_PUSH(x);
+
+ }
+ break;
+ case 58: {
+ /* supported-hash-functions */
+
+ int i;
+ unsigned x, num;
+
+ x = 0;
+ num = 0;
+ for (i = br_sha1_ID; i <= br_sha512_ID; i ++) {
+ if (br_multihash_getimpl(&ENG->mhash, i)) {
+ x |= 1U << i;
+ num ++;
+ }
+ }
+ T0_PUSH(x);
+ T0_PUSH(num);
+
+ }
+ break;
+ case 59: {
+ /* swap */
+ T0_SWAP();
+ }
+ break;
+ case 60: {
+ /* switch-aesgcm-in */
+
+ int is_client, prf_id;
+ unsigned cipher_key_len;
+
+ cipher_key_len = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_gcm_in(ENG, is_client, prf_id,
+ ENG->iaes_ctr, cipher_key_len);
+
+ }
+ break;
+ case 61: {
+ /* switch-aesgcm-out */
+
+ int is_client, prf_id;
+ unsigned cipher_key_len;
+
+ cipher_key_len = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_gcm_out(ENG, is_client, prf_id,
+ ENG->iaes_ctr, cipher_key_len);
+
+ }
+ break;
+ case 62: {
+ /* switch-cbc-in */
+
+ int is_client, prf_id, mac_id, aes;
+ unsigned cipher_key_len;
+
+ cipher_key_len = T0_POP();
+ aes = T0_POP();
+ mac_id = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_cbc_in(ENG, is_client, prf_id, mac_id,
+ aes ? ENG->iaes_cbcdec : ENG->ides_cbcdec, cipher_key_len);
+
+ }
+ break;
+ case 63: {
+ /* switch-cbc-out */
+
+ int is_client, prf_id, mac_id, aes;
+ unsigned cipher_key_len;
+
+ cipher_key_len = T0_POP();
+ aes = T0_POP();
+ mac_id = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_cbc_out(ENG, is_client, prf_id, mac_id,
+ aes ? ENG->iaes_cbcenc : ENG->ides_cbcenc, cipher_key_len);
+
+ }
+ break;
+ case 64: {
+ /* total-chain-length */
+
+ size_t u;
+ uint32_t total;
+
+ total = 0;
+ for (u = 0; u < CTX->chain_len; u ++) {
+ total += 3 + (uint32_t)CTX->chain[u].data_len;
+ }
+ T0_PUSH(total);
+
+ }
+ break;
+ case 65: {
+ /* u>> */
+
+ int c = (int)T0_POPi();
+ uint32_t x = T0_POP();
+ T0_PUSH(x >> c);
+
+ }
+ break;
+ case 66: {
+ /* write-blob-chunk */
+
+ size_t clen = ENG->hlen_out;
+ if (clen > 0) {
+ uint32_t addr, len;
+
+ len = T0_POP();
+ addr = T0_POP();
+ if ((size_t)len < clen) {
+ clen = (size_t)len;
+ }
+ memcpy(ENG->hbuf_out, (unsigned char *)ENG + addr, clen);
+ if (ENG->record_type_out == BR_SSL_HANDSHAKE) {
+ br_multihash_update(&ENG->mhash, ENG->hbuf_out, clen);
+ }
+ T0_PUSH(addr + (uint32_t)clen);
+ T0_PUSH(len - (uint32_t)clen);
+ ENG->hbuf_out += clen;
+ ENG->hlen_out -= clen;
+ }
+
+ }
+ break;
+ case 67: {
+ /* write8-native */
+
+ unsigned char x;
+
+ x = (unsigned char)T0_POP();
+ if (ENG->hlen_out > 0) {
+ if (ENG->record_type_out == BR_SSL_HANDSHAKE) {
+ br_multihash_update(&ENG->mhash, &x, 1);
+ }
+ *ENG->hbuf_out ++ = x;
+ ENG->hlen_out --;
+ T0_PUSHi(-1);
+ } else {
+ T0_PUSHi(0);
+ }
+
+ }
+ break;
+ }
+
+ } else {
+ T0_ENTER(ip, rp, t0x);
+ }
+ }
+t0_exit:
+ ((t0_context *)t0ctx)->dp = dp;
+ ((t0_context *)t0ctx)->rp = rp;
+ ((t0_context *)t0ctx)->ip = ip;
+}
--- /dev/null
+\ 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.
+
+\ ----------------------------------------------------------------------
+\ Handshake processing code, for the server.
+\ The common T0 code (ssl_hs_common.t0) shall be read first.
+
+preamble {
+
+/*
+ * This macro evaluates to a pointer to the server context, under that
+ * specific name. It must be noted that since the engine context is the
+ * first field of the br_ssl_server_context structure ('eng'), then
+ * pointers values of both types are interchangeable, modulo an
+ * appropriate cast. This also means that "adresses" computed as offsets
+ * within the structure work for both kinds of context.
+ */
+#define CTX ((br_ssl_server_context *)ENG)
+
+/*
+ * Decrypt the pre-master secret (RSA key exchange).
+ */
+static void
+do_rsa_decrypt(br_ssl_server_context *ctx, int prf_id,
+ unsigned char *epms, size_t len)
+{
+ uint32_t x;
+ unsigned char rpms[48];
+
+ /*
+ * Decrypt the PMS.
+ */
+ x = (*ctx->policy_vtable)->do_keyx(ctx->policy_vtable, epms, len);
+
+ /*
+ * Set the first two bytes to the maximum supported client
+ * protocol version. These bytes are used for version rollback
+ * detection; forceing the two bytes will make the master secret
+ * wrong if the bytes are not correct. This process is
+ * recommended by RFC 5246 (section 7.4.7.1).
+ */
+ br_enc16be(epms, ctx->client_max_version);
+
+ /*
+ * Make a random PMS and copy it above the decrypted value if the
+ * decryption failed. Note that we use a constant-time conditional
+ * copy.
+ */
+ br_hmac_drbg_generate(&ctx->eng.rng, rpms, sizeof rpms);
+ br_ccopy(x ^ 1, epms, rpms, sizeof rpms);
+
+ /*
+ * Compute master secret.
+ */
+ br_ssl_engine_compute_master(&ctx->eng, prf_id, epms, 48);
+
+ /*
+ * Clear the pre-master secret from RAM: it is normally a buffer
+ * in the context, hence potentially long-lived.
+ */
+ memset(epms, 0, len);
+}
+
+/*
+ * Common part for ECDH and ECDHE.
+ */
+static void
+ecdh_common(br_ssl_server_context *ctx, int prf_id,
+ unsigned char *cpoint, size_t cpoint_len, uint32_t ctl)
+{
+ unsigned char rpms[80];
+ size_t pms_len;
+
+ /*
+ * The point length is supposed to be 1+2*Xlen, where Xlen is
+ * the length (in bytes) of the X coordinate, i.e. the pre-master
+ * secret. If the provided point is too large, then it is
+ * obviously incorrect (i.e. everybody can see that it is
+ * incorrect), so leaking that fact is not a problem.
+ */
+ pms_len = cpoint_len >> 1;
+ if (pms_len > sizeof rpms) {
+ pms_len = sizeof rpms;
+ ctl = 0;
+ }
+
+ /*
+ * Make a random PMS and copy it above the decrypted value if the
+ * decryption failed. Note that we use a constant-time conditional
+ * copy.
+ */
+ br_hmac_drbg_generate(&ctx->eng.rng, rpms, pms_len);
+ br_ccopy(ctl ^ 1, cpoint + 1, rpms, pms_len);
+
+ /*
+ * Compute master secret.
+ */
+ br_ssl_engine_compute_master(&ctx->eng, prf_id, cpoint + 1, pms_len);
+
+ /*
+ * Clear the pre-master secret from RAM: it is normally a buffer
+ * in the context, hence potentially long-lived.
+ */
+ memset(cpoint, 0, cpoint_len);
+}
+
+/*
+ * Do the ECDH key exchange (not ECDHE).
+ */
+static void
+do_ecdh(br_ssl_server_context *ctx, int prf_id,
+ unsigned char *cpoint, size_t cpoint_len)
+{
+ uint32_t x;
+
+ /*
+ * Finalise the key exchange.
+ */
+ x = (*ctx->policy_vtable)->do_keyx(ctx->policy_vtable,
+ cpoint, cpoint_len);
+ ecdh_common(ctx, prf_id, cpoint, cpoint_len, x);
+}
+
+/*
+ * Do the ECDHE key exchange (part 1: generation of transient key, and
+ * computing of the point to send to the client). Returned value is the
+ * signature length (in bytes), or -x on error (with x being an error
+ * code). The encoded point is written in the ecdhe_point[] context buffer
+ * (length in ecdhe_point_len).
+ */
+static int
+do_ecdhe_part1(br_ssl_server_context *ctx, int curve)
+{
+ int hash;
+ unsigned mask;
+ const unsigned char *order, *generator;
+ size_t olen, glen;
+ br_multihash_context mhc;
+ unsigned char head[4];
+ size_t hv_len, sig_len;
+
+ if (!((ctx->eng.iec->supported_curves >> curve) & 1)) {
+ return -BR_ERR_INVALID_ALGORITHM;
+ }
+ ctx->eng.ecdhe_curve = curve;
+
+ /*
+ * Generate our private key. We need a non-zero random value
+ * which is lower than the curve order, in a "large enough"
+ * range. We force the top bit to 0 and bottom bit to 1, which
+ * does the trick. Note that contrary to what happens in ECDSA,
+ * this is not a problem if we do not cover the full range of
+ * possible values.
+ */
+ order = ctx->eng.iec->order(curve, &olen);
+ mask = 0xFF;
+ while (mask >= order[0]) {
+ mask >>= 1;
+ }
+ br_hmac_drbg_generate(&ctx->eng.rng, ctx->ecdhe_key, olen);
+ ctx->ecdhe_key[0] &= mask;
+ ctx->ecdhe_key[olen - 1] |= 0x01;
+ ctx->ecdhe_key_len = olen;
+
+ /*
+ * Compute our ECDH point.
+ */
+ generator = ctx->eng.iec->generator(curve, &glen);
+ memcpy(ctx->eng.ecdhe_point, generator, glen);
+ ctx->eng.ecdhe_point_len = glen;
+ if (!ctx->eng.iec->mul(ctx->eng.ecdhe_point, glen,
+ ctx->ecdhe_key, olen, curve))
+ {
+ return -BR_ERR_INVALID_ALGORITHM;
+ }
+
+ /*
+ * Compute the signature.
+ */
+ br_multihash_zero(&mhc);
+ br_multihash_copyimpl(&mhc, &ctx->eng.mhash);
+ br_multihash_init(&mhc);
+ br_multihash_update(&mhc,
+ ctx->eng.client_random, sizeof ctx->eng.client_random);
+ br_multihash_update(&mhc,
+ ctx->eng.server_random, sizeof ctx->eng.server_random);
+ head[0] = 3;
+ head[1] = 0;
+ head[2] = curve;
+ head[3] = ctx->eng.ecdhe_point_len;
+ br_multihash_update(&mhc, head, sizeof head);
+ br_multihash_update(&mhc,
+ ctx->eng.ecdhe_point, ctx->eng.ecdhe_point_len);
+ hash = ctx->sign_hash_id;
+ if (hash) {
+ hv_len = br_multihash_out(&mhc, hash, ctx->eng.pad);
+ if (hv_len == 0) {
+ return -BR_ERR_INVALID_ALGORITHM;
+ }
+ } else {
+ if (!br_multihash_out(&mhc, br_md5_ID, ctx->eng.pad)
+ || !br_multihash_out(&mhc,
+ br_sha1_ID, ctx->eng.pad + 16))
+ {
+ return -BR_ERR_INVALID_ALGORITHM;
+ }
+ hv_len = 36;
+ }
+ sig_len = (*ctx->policy_vtable)->do_sign(ctx->policy_vtable,
+ hash, hv_len, ctx->eng.pad, sizeof ctx->eng.pad);
+ return sig_len ? (int)sig_len : -BR_ERR_INVALID_ALGORITHM;
+}
+
+/*
+ * Do the ECDHE key exchange (part 2: computation of the shared secret
+ * from the point sent by the client).
+ */
+static void
+do_ecdhe_part2(br_ssl_server_context *ctx, int prf_id,
+ unsigned char *cpoint, size_t cpoint_len)
+{
+ int curve;
+ uint32_t x;
+
+ curve = ctx->eng.ecdhe_curve;
+
+ /*
+ * Finalise the key exchange.
+ */
+ x = ctx->eng.iec->mul(cpoint, cpoint_len,
+ ctx->ecdhe_key, ctx->ecdhe_key_len, curve);
+ ecdh_common(ctx, prf_id, cpoint, cpoint_len, x);
+
+ /*
+ * Clear the ECDHE private key. Forward Secrecy is achieved insofar
+ * as that key does not get stolen, so we'd better destroy it
+ * as soon as it ceases to be useful.
+ */
+ memset(ctx->ecdhe_key, 0, ctx->ecdhe_key_len);
+}
+
+}
+
+\ =======================================================================
+
+: addr-ctx:
+ next-word { field }
+ "addr-" field + 0 1 define-word
+ 0 8191 "offsetof(br_ssl_server_context, " field + ")" + make-CX
+ postpone literal postpone ; ;
+
+addr-ctx: flags
+addr-ctx: client_max_version
+addr-ctx: client_suites
+addr-ctx: client_suites_num
+addr-ctx: hashes
+addr-ctx: curves
+addr-ctx: sign_hash_id
+
+\ Get address and length of the client_suites[] buffer. Length is expressed
+\ in bytes.
+: addr-len-client_suites ( -- addr len )
+ addr-client_suites
+ CX 0 1023 { BR_MAX_CIPHER_SUITES * sizeof(br_suite_translated) } ;
+
+\ Check a server flag by index.
+: flag? ( index -- bool )
+ addr-flags get32 swap >> 1 and neg ;
+
+\ Read the client SNI extension.
+: read-client-sni ( lim -- lim )
+ \ Open extension value.
+ read16 open-elt
+
+ \ Open ServerNameList.
+ read16 open-elt
+
+ \ Find if there is a name of type 0 (host_name) with a length
+ \ that fits in our dedicated buffer.
+ begin dup while
+ read8 if
+ read-ignore-16
+ else
+ read16
+ dup 255 <= if
+ dup addr-server_name + 0 swap set8
+ addr-server_name swap read-blob
+ else
+ skip-blob
+ then
+ then
+ repeat
+
+ \ Close ServerNameList.
+ close-elt
+
+ \ Close extension value.
+ close-elt ;
+
+\ Set the new maximum fragment length. BEWARE: this shall be called only
+\ after reading the ClientHello and before writing the ServerHello.
+cc: set-max-frag-len ( len -- ) {
+ size_t max_frag_len = T0_POP();
+
+ br_ssl_engine_new_max_frag_len(ENG, max_frag_len);
+
+ /*
+ * We must adjust our own output limit. Since we call this only
+ * after receiving a ClientHello and before beginning to send
+ * the ServerHello, the next output record should be empty at
+ * that point, so we can use max_frag_len as a limit.
+ */
+ if (ENG->hlen_out > max_frag_len) {
+ ENG->hlen_out = max_frag_len;
+ }
+}
+
+\ Read the client Max Frag Length extension.
+: read-client-frag ( lim -- lim )
+ \ Extension value must have length exactly 1 byte.
+ read16 1 <> if ERR_BAD_FRAGLEN fail then
+ read8
+
+ \ The byte value must be 1, 2, 3 or 4.
+ dup dup 0= swap 5 >= or if ERR_BAD_FRAGLEN fail then
+
+ \ If our own maximum fragment length is greater, then we reduce
+ \ our length.
+ 8 + dup addr-log_max_frag_len get8 < if
+ dup 1 swap << set-max-frag-len
+ dup addr-log_max_frag_len set8
+ addr-peer_log_max_frag_len set8
+ else
+ drop
+ then ;
+
+\ Read the Secure Renegotiation extension from the client.
+: read-client-reneg ( lim -- lim )
+ \ Get value length.
+ read16
+
+ \ The "reneg" value is one of:
+ \ 0 on first handshake, client support is unknown
+ \ 1 client does not support secure renegotiation
+ \ 2 client supports secure renegotiation
+ addr-reneg get8 case
+ 0 of
+ \ First handshake, value length shall be 1.
+ 1 = ifnot ERR_BAD_SECRENEG fail then
+ read8 if ERR_BAD_SECRENEG fail then
+ 2 addr-reneg set8
+ endof
+ 2 of
+ \ Renegotiation, value shall consist of 13 bytes
+ \ (header + copy of the saved client "Finished").
+ 13 = ifnot ERR_BAD_SECRENEG fail then
+ read8 12 = ifnot ERR_BAD_SECRENEG fail then
+ addr-pad 12 read-blob
+ addr-saved_finished addr-pad 12 memcmp ifnot
+ ERR_BAD_SECRENEG fail
+ then
+ endof
+
+ \ If "reneg" is 1 then the client is not supposed to support
+ \ the extension, and it sends it nonetheless, which means
+ \ foul play.
+ ERR_BAD_SECRENEG fail
+ endcase ;
+
+\ Read the Signature Algorithms extension.
+: read-signatures ( lim -- lim )
+ \ Open extension value.
+ read16 open-elt
+
+ \ Clear list of supported signature algorithms.
+ 0 addr-hashes set16
+
+ \ Get list of algorithms length.
+ read16 open-elt
+ begin dup while
+ read8 { hash } read8 { sign }
+ \ We keep the value if the signature is either 1 (RSA) or
+ \ 3 (ECDSA), and the hash is one of the SHA-* functions
+ \ (2 to 6, from SHA-1 to SHA-512). Note that we reject
+ \ any use of MD5. Also, we do not keep track of the client
+ \ preferences.
+ hash 2 >= hash 6 <= and
+ sign 1 = sign 3 = or
+ and if
+ addr-hashes get16
+ 1 sign 1- 2 << hash + << or addr-hashes set16
+ then
+ repeat
+ close-elt
+
+ \ Close extension value.
+ close-elt ;
+
+\ Read the Supported Curves extension.
+: read-supported-curves ( lim -- lim )
+ \ Open extension value.
+ read16 open-elt
+
+ \ Open list of curve identifiers.
+ read16 open-elt
+
+ \ Get all supported curves.
+ 0 addr-curves set32
+ begin dup while
+ read16 dup 32 < if
+ 1 swap << addr-curves get32 or addr-curves set32
+ else
+ drop
+ then
+ repeat
+ close-elt
+ close-elt ;
+
+\ Call policy handler to get cipher suite, hash function identifier and
+\ certificate chain. Returned value is 0 (false) on failure.
+cc: call-policy-handler ( -- bool ) {
+ int x;
+ br_ssl_server_choices choices;
+
+ x = (*CTX->policy_vtable)->choose(
+ CTX->policy_vtable, CTX, &choices);
+ ENG->session.cipher_suite = choices.cipher_suite;
+ CTX->sign_hash_id = choices.hash_id;
+ CTX->chain = choices.chain;
+ CTX->chain_len = choices.chain_len;
+ T0_PUSHi(-(x != 0));
+}
+
+\ Check for a remembered session.
+cc: check-resume ( -- bool ) {
+ if (ENG->session.session_id_len == 32
+ && CTX->cache_vtable != NULL && (*CTX->cache_vtable)->load(
+ CTX->cache_vtable, CTX, &ENG->session))
+ {
+ T0_PUSHi(-1);
+ } else {
+ T0_PUSH(0);
+ }
+}
+
+\ Save the current session.
+cc: save-session ( -- ) {
+ if (CTX->cache_vtable != NULL) {
+ (*CTX->cache_vtable)->save(
+ CTX->cache_vtable, CTX, &ENG->session);
+ }
+}
+
+\ Read ClientHello. If the session is resumed, then -1 is returned.
+: read-ClientHello ( -- resume )
+ \ Get header, and check message type.
+ read-handshake-header 1 = ifnot ERR_UNEXPECTED fail then
+
+ \ Get maximum protocol version from client.
+ read16 dup { client-version-max } addr-client_max_version set16
+
+ \ Client random.
+ addr-client_random 32 read-blob
+
+ \ Client session ID.
+ read8 dup 32 > if ERR_OVERSIZED_ID fail then
+ dup addr-session_id_len set8
+ addr-session_id swap read-blob
+
+ \ Lookup session for resumption. We should do that here because
+ \ we need to verify that the remembered cipher suite is still
+ \ matched by this ClientHello.
+ check-resume { resume }
+
+ \ Cipher suites. We read all cipher suites from client, each time
+ \ matching against our own list. We accumulare suites in the
+ \ client_suites[] context buffer: we keep suites that are
+ \ supported by both the client and the server (so the list size
+ \ cannot exceed that of the server list), and we keep them in
+ \ either client or server preference order (depending on the
+ \ relevant flag).
+ \
+ \ We also need to identify the pseudo cipher suite for secure
+ \ renegotiation here.
+ read16 open-elt
+ 0 { reneg-scsv }
+ 0 { resume-suite }
+ addr-len-client_suites dup2 bzero
+ over + { css-off css-max }
+ begin
+ dup while
+ read16 dup { suite }
+
+ \ Check that when resuming a session, the requested
+ \ suite is still valid.
+ resume if
+ dup addr-cipher_suite get16 = if
+ -1 >resume-suite
+ then
+ then
+
+ \ Special handling for TLS_EMPTY_RENEGOTIATION_INFO_SCSV.
+ \ This fake cipher suite may occur only in the first
+ \ handshake.
+ dup 0x00FF = if
+ addr-reneg get8 if ERR_BAD_SECRENEG fail then
+ -1 >reneg-scsv
+ then
+
+ \ Test whether the suite is supported by the server.
+ scan-suite dup 0< if
+ \ We do not support this cipher suite. Note
+ \ that this also covers the case of pseudo
+ \ cipher suites.
+ drop
+ else
+ \ If we use server order, then we place the
+ \ suite at the computed offset; otherwise, we
+ \ append it to the list at the current place.
+ 0 flag? if
+ 2 << addr-client_suites + suite swap set16
+ else
+ drop
+ \ We need to test for list length because
+ \ the client list may have duplicates,
+ \ that we do not filter. Duplicates are
+ \ invalid so this is not a problem if we
+ \ reject such clients.
+ css-off css-max >= if
+ ERR_BAD_HANDSHAKE fail
+ then
+ suite css-off set16
+ css-off 4 + >css-off
+ then
+ then
+ repeat
+ drop
+
+ \ Compression methods. We need method 0 (no compression).
+ 0 { ok-compression }
+ read8 open-elt
+ begin dup while
+ read8 ifnot -1 >ok-compression then
+ repeat
+ close-elt
+
+ \ Set default values for parameters that may be affected by
+ \ extensions:
+ \ -- server name is empty
+ \ -- client is reputed to know RSA and ECDSA, both with SHA-1
+ \ -- the default elliptic curve is P-256 (secp256r1, id = 23)
+ 0 addr-server_name set8
+ 0x404 addr-hashes set16
+ 0x800000 addr-curves set32
+
+ \ Process extensions, if any.
+ dup if
+ read16 open-elt
+ begin dup while
+ read16 case
+ \ Server Name Indication.
+ 0x0000 of
+ read-client-sni
+ endof
+ \ Max Frag Length.
+ 0x0001 of
+ read-client-frag
+ endof
+ \ Secure Renegotiation.
+ 0xFF01 of
+ read-client-reneg
+ endof
+ \ Signature Algorithms.
+ 0x000D of
+ read-signatures
+ endof
+ \ Supported Curves.
+ 0x000A of
+ read-supported-curves
+ endof
+ \ Supported Point Formats.
+ 0x000B of
+ \ We only support "uncompressed", and
+ \ all implementations are supposed to
+ \ support it anyway.
+ read-ignore-16
+ endof
+
+ \ Other extensions are ignored.
+ drop read-ignore-16 0
+ endcase
+ repeat
+ close-elt
+ then
+
+ \ Close message.
+ close-elt
+
+ \ Cancel session resumption if the cipher suite was not found.
+ resume resume-suite and >resume
+
+ \ Now check the received data. Since the client is expecting an
+ \ answer, we can send an appropriate fatal alert on any error.
+
+ \ Compute protocol version as the minimum of our maximum version,
+ \ and the maximum version sent by the client. If that is less than
+ \ 0x0300 (SSL-3.0), then fail. Otherwise, we may at least send an
+ \ alert with that version. We still reject versions lower than our
+ \ configured minimum.
+ addr-version_max get16
+ dup client-version-max > if drop client-version-max then
+ dup 0x0300 < if ERR_BAD_VERSION fail then
+ client-version-max addr-version_min get16 < if
+ 70 fail-alert
+ then
+ \ If resuming the session, then enforce the previously negotiated
+ \ version (if still possible).
+ resume if
+ addr-version get16 client-version-max <= if
+ drop addr-version get16
+ else
+ 0 >resume
+ then
+ then
+ dup addr-version set16
+ dup addr-version_in set16
+ dup addr-version_out set16
+ 0x0303 >= { can-tls12 }
+
+ \ If the client sent TLS_EMPTY_RENEGOTIATION_INFO_SCSV, then
+ \ we should mark the client as "supporting secure renegotiation".
+ reneg-scsv if 2 addr-reneg set8 then
+
+ \ Check compression.
+ ok-compression ifnot 40 fail-alert then
+
+ \ Filter hash function support by what the server also supports.
+ \ If no common hash function remains, then ECDHE suites are not
+ \ possible.
+ supported-hash-functions drop 257 *
+ addr-hashes get16 and dup addr-hashes set16
+ 0<> { can-ecdhe }
+
+ \ Filter supported curves. If there is no common curve between
+ \ client and us, then ECDHE suites cannot be used. Note that we
+ \ may still allow ECDH, depending on the EC key handler.
+ addr-curves get32 supported-curves and dup addr-curves set32
+ ifnot 0 >can-ecdhe then
+
+ \ If resuming a session, then the next steps are not necessary;
+ \ we won't invoke the policy handler.
+ resume if -1 ret then
+
+ \ We are not resuming, so a new session ID should be generated.
+ addr-session_id 32 mkrand
+
+ \ Translate common cipher suites, then squeeze out holes: there
+ \ may be holes because of the way we fill the list when the
+ \ server preference order is enforced, and also in case some
+ \ suites are filtered out. In particular:
+ \ -- ECDHE suites are removed if there is no common hash function
+ \ (for signatures) or no common curve.
+ \ -- TLS-1.2-only suites are removed if the negociated version is
+ \ TLS-1.1 or lower.
+ addr-client_suites dup >css-off
+ begin dup css-max < while
+ dup get16 dup cipher-suite-to-elements
+ can-ecdhe ifnot
+ dup 12 >> dup 1 = swap 2 = or if
+ 2drop 0 dup
+ then
+ then
+ can-tls12 ifnot
+ \ Suites compatible with TLS-1.0 and TLS-1.1 are
+ \ exactly the ones that use HMAC/SHA-1.
+ dup 0xF0 and 0x20 <> if
+ 2drop 0 dup
+ then
+ then
+ dup if
+ css-off 2+ set16 css-off set16
+ css-off 4 + >css-off
+ else
+ 2drop
+ then
+ 4 +
+ repeat
+ drop
+ css-off addr-client_suites - 2 >>
+ dup ifnot
+ \ No common cipher suite: handshake failure.
+ 40 fail-alert
+ then
+ addr-client_suites_num set8
+
+ \ Call policy handler to obtain the cipher suite and other
+ \ parameters.
+ call-policy-handler ifnot 40 fail-alert then
+
+ \ We are not resuming a session.
+ 0 ;
+
+\ Write ServerHello.
+: write-ServerHello ( initial -- )
+ { initial }
+ \ Compute ServerHello length. Right now we only send the
+ \ "secure renegotiation" extension.
+ 2 write8 70
+
+ addr-reneg get8 2 = if
+ initial if 5 else 29 then
+ else
+ 0
+ then
+ { ext-reneg-len }
+ addr-peer_log_max_frag_len get8 if 5 else 0 then
+ { ext-max-frag-len }
+
+ ext-reneg-len ext-max-frag-len + dup if 2 + then +
+ write24
+
+ \ Protocol version
+ addr-version get16 write16
+
+ \ Server random
+ addr-server_random 4 bzero
+ addr-server_random 4 + 28 mkrand
+ addr-server_random 32 write-blob
+
+ \ Session ID
+ \ TODO: if we have no session cache at all, we might send here
+ \ an empty session ID. This would save a bit of network
+ \ bandwidth.
+ 32 write8
+ addr-session_id 32 write-blob
+
+ \ Cipher suite
+ addr-cipher_suite get16 write16
+
+ \ Compression method
+ 0 write8
+
+ \ Extensions
+ ext-reneg-len ext-max-frag-len + dup if
+ write16
+ ext-reneg-len dup if
+ 0xFF01 write16
+ 4 - dup write16
+ 1- addr-saved_finished swap write-blob-head8
+ else
+ drop
+ then
+ ext-max-frag-len if
+ 0x0001 write16
+ 1 write16 addr-peer_log_max_frag_len get8 8 - write8
+ then
+ else
+ drop
+ then ;
+
+\ Compute total chain length. This includes the individual certificate
+\ headers, but not the total chain header. This also sets the cert_cur,
+\ cert_len and chain_len context fields.
+cc: total-chain-length ( -- len ) {
+ size_t u;
+ uint32_t total;
+
+ total = 0;
+ for (u = 0; u < CTX->chain_len; u ++) {
+ total += 3 + (uint32_t)CTX->chain[u].data_len;
+ }
+ T0_PUSH(total);
+}
+
+\ Get length for current certificate in the chain; if the chain end was
+\ reached, then this returns -1.
+cc: begin-cert ( -- len ) {
+ if (CTX->chain_len == 0) {
+ T0_PUSHi(-1);
+ } else {
+ CTX->cert_cur = CTX->chain->data;
+ CTX->cert_len = CTX->chain->data_len;
+ CTX->chain ++;
+ CTX->chain_len --;
+ T0_PUSH(CTX->cert_len);
+ }
+}
+
+\ Copy a chunk of certificate data into the pad. Returned value is the
+\ chunk length, or 0 if the certificate end is reached.
+cc: copy-cert-chunk ( -- len ) {
+ size_t clen;
+
+ clen = CTX->cert_len;
+ if (clen > sizeof ENG->pad) {
+ clen = sizeof ENG->pad;
+ }
+ memcpy(ENG->pad, CTX->cert_cur, clen);
+ CTX->cert_cur += clen;
+ CTX->cert_len -= clen;
+ T0_PUSH(clen);
+}
+
+\ Write the server Certificate.
+: write-Certificate ( -- )
+ 11 write8
+ total-chain-length
+ dup 3 + write24 write24
+ begin
+ begin-cert
+ dup 0< if drop ret then write24
+ begin copy-cert-chunk dup while
+ addr-pad swap write-blob
+ repeat
+ drop
+ again ;
+
+\ Do the first part of ECDHE. Returned value is the computed signature
+\ length, or a negative error code on error.
+cc: do-ecdhe-part1 ( curve -- len ) {
+ int curve = T0_POPi();
+ T0_PUSHi(do_ecdhe_part1(CTX, curve));
+}
+
+\ Write the Server Key Exchange message (if applicable).
+: write-ServerKeyExchange ( -- )
+ addr-cipher_suite get16 use-ecdhe? ifnot ret then
+
+ \ We must select an appropriate curve among the curves that
+ \ are supported both by us and the peer. Right now we use
+ \ the one with the smallest ID, which in practice means P-256.
+ \ (TODO: add some option to make that behaviour configurable.)
+ \
+ \ This loop always terminates because previous processing made
+ \ sure that ECDHE suites are not selectable if there is no common
+ \ curve.
+ addr-curves get32 0
+ begin dup2 >> 1 and 0= while 1+ repeat
+ { curve-id } drop
+
+ \ Compute the signed curve point to send.
+ curve-id do-ecdhe-part1 dup 0< if neg fail then { sig-len }
+
+ \ If using TLS-1.2+, then the hash function and signature
+ \ algorithm are explicitly encoded in the message.
+ addr-version get16 0x0303 >= { tls1.2+ }
+
+ 12 write8
+ sig-len addr-ecdhe_point_len get8 + tls1.2+ 2 and + 6 + write24
+
+ \ Curve parameters: named curve with 16-bit ID.
+ 3 write8 curve-id write16
+
+ \ Public point.
+ addr-ecdhe_point addr-ecdhe_point_len get8 write-blob-head8
+
+ \ If TLS-1.2+, write hash and signature identifiers.
+ tls1.2+ if
+ \ Hash identifier is in the sign_hash_id field.
+ addr-sign_hash_id get8 write8
+ \ 'use-rsa-ecdhe?' returns -1 for RSA, 0 for ECDSA.
+ \ The byte on the wire shall be 1 for RSA, 3 for ECDSA.
+ addr-cipher_suite get16 use-rsa-ecdhe? 1 << 3 + write8
+ then
+
+ \ Signature.
+ sig-len write16
+ addr-pad sig-len write-blob ;
+
+\ Write the Server Hello Done message.
+: write-ServerHelloDone ( -- )
+ 14 write8 0 write24 ;
+
+\ Perform RSA decryption of the client-sent pre-master secret. The value
+\ is in the pad, and its length is provided as parameter.
+cc: do-rsa-decrypt ( len prf_id -- ) {
+ int prf_id = T0_POPi();
+ size_t len = T0_POP();
+ do_rsa_decrypt(CTX, prf_id, ENG->pad, len);
+}
+
+\ Perform ECDH (not ECDHE). The point from the client is in the pad, and
+\ its length is provided as parameter.
+cc: do-ecdh ( len prf_id -- ) {
+ int prf_id = T0_POPi();
+ size_t len = T0_POP();
+ do_ecdh(CTX, prf_id, ENG->pad, len);
+}
+
+\ Do the second part of ECDHE.
+cc: do-ecdhe-part2 ( len prf_id -- ) {
+ int prf_id = T0_POPi();
+ size_t len = T0_POP();
+ do_ecdhe_part2(CTX, prf_id, ENG->pad, len);
+}
+
+\ Read the Client Key Exchange.
+: read-ClientKeyExchange ( -- )
+ \ Get header, and check message type.
+ read-handshake-header 16 = ifnot ERR_UNEXPECTED fail then
+
+ \ What we should get depends on the cipher suite.
+ addr-cipher_suite get16 use-rsa-keyx? if
+ \ RSA key exchange: we expect a RSA-encrypted value.
+ read16
+ dup 512 > if ERR_LIMIT_EXCEEDED fail then
+ dup { enc-rsa-len }
+ addr-pad swap read-blob
+ enc-rsa-len addr-cipher_suite get16 prf-id do-rsa-decrypt
+ then
+ addr-cipher_suite get16 dup use-ecdhe? swap use-ecdh? { ecdhe ecdh }
+ ecdh ecdhe or if
+ \ ECDH or ECDHE key exchange: we expect an EC point.
+ read8 dup { ec-point-len }
+ addr-pad swap read-blob
+ ec-point-len addr-cipher_suite get16 prf-id
+ ecdhe if do-ecdhe-part2 else do-ecdh then
+ then
+ close-elt ;
+
+\ Send a HelloRequest.
+: send-HelloRequest ( -- )
+ flush-record
+ begin can-output? not while wait-co drop repeat
+ 22 addr-record_type_out set8
+ 0 write8 0 write24 flush-record
+ 23 addr-record_type_out set8 ;
+
+\ Make a handshake.
+: do-handshake ( initial -- )
+ 0 addr-application_data set8
+ 22 addr-record_type_out set8
+ multihash-init
+ read-ClientHello
+ more-incoming-bytes? if ERR_UNEXPECTED fail then
+ if
+ \ Session resumption
+ write-ServerHello
+ 0 write-CCS-Finished
+ 0 read-CCS-Finished
+ else
+ \ Not a session resumption
+ write-ServerHello
+ write-Certificate
+ write-ServerKeyExchange
+ write-ServerHelloDone
+ flush-record
+ read-ClientKeyExchange
+ 0 read-CCS-Finished
+ 0 write-CCS-Finished
+ save-session
+ then
+ 1 addr-application_data set8
+ 23 addr-record_type_out set8 ;
+
+\ Entry point.
+: main ( -- ! )
+ \ Perform initial handshake.
+ -1 do-handshake
+
+ begin
+ \ Wait for further invocation. At that point, we should
+ \ get either an explicit call for renegotiation, or
+ \ an incoming ClientHello handshake message.
+ wait-co
+ dup 0x07 and case
+ 0x00 of
+ 0x10 and if
+ \ The best we can do is ask for a
+ \ renegotiation, then wait for it
+ \ to happen.
+ send-HelloRequest
+ then
+ endof
+ 0x01 of
+ \ Reject renegotiations if the peer does not
+ \ support secure renegotiation. As allowed
+ \ by RFC 5246, we do not send a
+ \ no_renegotiation alert and just ignore the
+ \ HelloRequest.
+ drop
+ addr-reneg get8 1 <> if
+ 0 do-handshake
+ else
+ flush-record
+ begin can-output? not while
+ wait-co drop
+ repeat
+ then
+ endof
+ ERR_UNEXPECTED fail
+ endcase
+ again
+ ;
--- /dev/null
+/*
+ * 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_ssl.h */
+void
+br_sslio_init(br_sslio_context *ctx,
+ br_ssl_engine_context *engine,
+ int (*low_read)(void *read_context,
+ unsigned char *data, size_t len),
+ void *read_context,
+ int (*low_write)(void *write_context,
+ const unsigned char *data, size_t len),
+ void *write_context)
+{
+ ctx->engine = engine;
+ ctx->low_read = low_read;
+ ctx->read_context = read_context;
+ ctx->low_write = low_write;
+ ctx->write_context = write_context;
+}
+
+/*
+ * Run the engine, until the specified target state is achieved, or
+ * an error occurs. The target state is SENDAPP, RECVAPP, or the
+ * combination of both (the combination matches either). When a match is
+ * achieved, this function returns 0. On error, it returns -1.
+ */
+static int
+run_until(br_sslio_context *ctx, unsigned target)
+{
+ for (;;) {
+ unsigned state;
+
+ state = br_ssl_engine_current_state(ctx->engine);
+ if (state & BR_SSL_CLOSED) {
+ return -1;
+ }
+
+ /*
+ * If there is some record data to send, do it. This takes
+ * precedence over everything else.
+ */
+ if (state & BR_SSL_SENDREC) {
+ unsigned char *buf;
+ size_t len;
+ int wlen;
+
+ buf = br_ssl_engine_sendrec_buf(ctx->engine, &len);
+ wlen = ctx->low_write(ctx->write_context, buf, len);
+ if (wlen < 0) {
+ /*
+ * If we received a close_notify and we
+ * still send something, then we have our
+ * own response close_notify to send, and
+ * the peer is allowed by RFC 5246 not to
+ * wait for it.
+ */
+ if (!ctx->engine->shutdown_recv) {
+ br_ssl_engine_fail(
+ ctx->engine, BR_ERR_IO);
+ }
+ return -1;
+ }
+ if (wlen > 0) {
+ br_ssl_engine_sendrec_ack(ctx->engine, wlen);
+ }
+ continue;
+ }
+
+ /*
+ * If we reached our target, then we are finished.
+ */
+ if (state & target) {
+ return 0;
+ }
+
+ /*
+ * If some application data must be read, and we did not
+ * exit, then this means that we are trying to write data,
+ * and that's not possible until the application data is
+ * read. This may happen if using a shared in/out buffer,
+ * and the underlying protocol is not strictly half-duplex.
+ * This is unrecoverable here, so we report an error.
+ */
+ if (state & BR_SSL_RECVAPP) {
+ return -1;
+ }
+
+ /*
+ * If we reached that point, then either we are trying
+ * to read data and there is some, or the engine is stuck
+ * until a new record is obtained.
+ */
+ if (state & BR_SSL_RECVREC) {
+ unsigned char *buf;
+ size_t len;
+ int rlen;
+
+ buf = br_ssl_engine_recvrec_buf(ctx->engine, &len);
+ rlen = ctx->low_read(ctx->read_context, buf, len);
+ if (rlen < 0) {
+ br_ssl_engine_fail(ctx->engine, BR_ERR_IO);
+ return -1;
+ }
+ if (rlen > 0) {
+ br_ssl_engine_recvrec_ack(ctx->engine, rlen);
+ }
+ continue;
+ }
+
+ /*
+ * We can reach that point if the target RECVAPP, and
+ * the state contains SENDAPP only. This may happen with
+ * a shared in/out buffer. In that case, we must flush
+ * the buffered data to "make room" for a new incoming
+ * record.
+ */
+ br_ssl_engine_flush(ctx->engine, 0);
+ }
+}
+
+/* see bearssl_ssl.h */
+int
+br_sslio_read(br_sslio_context *ctx, void *dst, size_t len)
+{
+ unsigned char *buf;
+ size_t alen;
+
+ if (run_until(ctx, BR_SSL_RECVAPP) < 0) {
+ return -1;
+ }
+ buf = br_ssl_engine_recvapp_buf(ctx->engine, &alen);
+ if (alen > len) {
+ alen = len;
+ }
+ memcpy(dst, buf, alen);
+ br_ssl_engine_recvapp_ack(ctx->engine, alen);
+ return (int)alen;
+}
+
+/* see bearssl_ssl.h */
+int
+br_sslio_read_all(br_sslio_context *ctx, void *dst, size_t len)
+{
+ unsigned char *buf;
+
+ buf = dst;
+ while (len > 0) {
+ int rlen;
+
+ rlen = br_sslio_read(ctx, buf, len);
+ if (rlen < 0) {
+ return -1;
+ }
+ buf += rlen;
+ len -= (size_t)rlen;
+ }
+ return 0;
+}
+
+/* see bearssl_ssl.h */
+int
+br_sslio_write(br_sslio_context *ctx, const void *src, size_t len)
+{
+ unsigned char *buf;
+ size_t alen;
+
+ if (run_until(ctx, BR_SSL_SENDAPP) < 0) {
+ return -1;
+ }
+ buf = br_ssl_engine_sendapp_buf(ctx->engine, &alen);
+ if (alen > len) {
+ alen = len;
+ }
+ memcpy(buf, src, alen);
+ br_ssl_engine_sendapp_ack(ctx->engine, alen);
+ return (int)alen;
+}
+
+/* see bearssl_ssl.h */
+int
+br_sslio_write_all(br_sslio_context *ctx, const void *src, size_t len)
+{
+ const unsigned char *buf;
+
+ buf = src;
+ while (len > 0) {
+ int wlen;
+
+ wlen = br_sslio_write(ctx, buf, len);
+ if (wlen < 0) {
+ return -1;
+ }
+ buf += wlen;
+ len -= (size_t)wlen;
+ }
+ return 0;
+}
+
+/* see bearssl_ssl.h */
+int
+br_sslio_flush(br_sslio_context *ctx)
+{
+ /*
+ * We trigger a flush. We know the data is gone when there is
+ * no longer any record data to send, and we can either read
+ * or write application data. The call to run_until() does the
+ * job because it ensures that any assembled record data is
+ * first sent down the wire before considering anything else.
+ */
+ br_ssl_engine_flush(ctx->engine, 0);
+ return run_until(ctx, BR_SSL_SENDAPP | BR_SSL_RECVAPP);
+}
+
+/* see bearssl_ssl.h */
+int
+br_sslio_close(br_sslio_context *ctx)
+{
+ br_ssl_engine_close(ctx->engine);
+ while (br_ssl_engine_current_state(ctx->engine) != BR_SSL_CLOSED) {
+ /*
+ * Discard any incoming application data.
+ */
+ size_t len;
+
+ run_until(ctx, BR_SSL_RECVAPP);
+ if (br_ssl_engine_recvapp_buf(ctx->engine, &len) != NULL) {
+ br_ssl_engine_recvapp_ack(ctx->engine, len);
+ }
+ }
+ return br_ssl_engine_last_error(ctx->engine) == BR_ERR_OK;
+}
--- /dev/null
+/*
+ * 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"
+
+/*
+ * Each entry consists in a fixed number of bytes. Entries are concatenated
+ * in the store block. "Addresses" are really offsets in the block,
+ * expressed over 32 bits (so the cache may have size at most 4 GB, which
+ * "ought to be enough for everyone"). The "null address" is 0xFFFFFFFF.
+ * Note that since the storage block alignment is in no way guaranted, we
+ * perform only accesses that can handle unaligned data.
+ *
+ * Two concurrent data structures are maintained:
+ *
+ * -- Entries are organised in a doubly-linked list; saved entries are added
+ * at the head, and loaded entries are moved to the head. Eviction uses
+ * the list tail (this is the LRU algorithm).
+ *
+ * -- Entries are indexed with a binary tree: all left descendants of a
+ * node have a lower session ID (in lexicographic order), while all
+ * right descendants have a higher session ID. The tree is balanced.
+ *
+ * Entry format:
+ *
+ * session ID 32 bytes
+ * master secret 48 bytes
+ * protocol version 2 bytes (big endian)
+ * cipher suite 2 bytes (big endian)
+ * list prev 4 bytes (big endian)
+ * list next 4 bytes (big endian)
+ * tree left child 4 bytes (big endian)
+ * tree right child 4 bytes (big endian)
+ * tree node colour 1 byte (0 = red, 1 = black)
+ *
+ * We need to keep the tree balanced because an attacker could make
+ * handshakes, selecting some specific sessions (by reusing them) to
+ * try to make us make an imbalanced tree that makes lookups expensive
+ * (a denial-of-service attack that would persist as long as the cache
+ * remains, i.e. even after the attacker made all his connections).
+ * To do that, we replace the session ID (or the start of the session ID)
+ * with a HMAC value computed over the replaced part; the hash function
+ * implementation and the key are obtained from the server context upon
+ * first save() call.
+ */
+#define SESSION_ID_LEN 32
+#define MASTER_SECRET_LEN 48
+
+#define SESSION_ID_OFF 0
+#define MASTER_SECRET_OFF 32
+#define VERSION_OFF 80
+#define CIPHER_SUITE_OFF 82
+#define LIST_PREV_OFF 84
+#define LIST_NEXT_OFF 88
+#define TREE_LEFT_OFF 92
+#define TREE_RIGHT_OFF 96
+
+#define LRU_ENTRY_LEN 100
+
+#define ADDR_NULL ((uint32_t)-1)
+
+#define GETSET(name, off) \
+static inline uint32_t get_ ## name(br_ssl_session_cache_lru *cc, uint32_t x) \
+{ \
+ return br_dec32be(cc->store + x + (off)); \
+} \
+static inline void set_ ## name(br_ssl_session_cache_lru *cc, \
+ uint32_t x, uint32_t val) \
+{ \
+ br_enc32be(cc->store + x + (off), val); \
+}
+
+GETSET(prev, LIST_PREV_OFF)
+GETSET(next, LIST_NEXT_OFF)
+GETSET(left, TREE_LEFT_OFF)
+GETSET(right, TREE_RIGHT_OFF)
+
+/*
+ * Transform the session ID by replacing the first N bytes with a HMAC
+ * value computed over these bytes, using the random key K (the HMAC
+ * value is truncated if needed). HMAC will use the same hash function
+ * as the DRBG in the SSL server context, so with SHA-256, SHA-384,
+ * or SHA-1, depending on what is available.
+ *
+ * The risk of collision is considered too small to be a concern; and
+ * the impact of a collision is low (the handshake won't succeed). This
+ * risk is much lower than any transmission error, which would lead to
+ * the same consequences.
+ */
+static void
+mask_id(br_ssl_session_cache_lru *cc,
+ const unsigned char *src, unsigned char *dst)
+{
+ br_hmac_key_context hkc;
+ br_hmac_context hc;
+
+ memcpy(dst, src, SESSION_ID_LEN);
+ br_hmac_key_init(&hkc, cc->hash, cc->index_key, sizeof cc->index_key);
+ br_hmac_init(&hc, &hkc, SESSION_ID_LEN);
+ br_hmac_update(&hc, src, SESSION_ID_LEN);
+ br_hmac_out(&hc, dst);
+}
+
+/*
+ * Find a node by ID. Returned value is the node address, or ADDR_NULL if
+ * the node is not found.
+ *
+ * If addr_link is not NULL, then '*addr_link' is set to the address of the
+ * last followed link. If the found node is the root, then '*addr_link' is
+ * set to ADDR_NULL.
+ */
+static uint32_t
+find_node(br_ssl_session_cache_lru *cc, const unsigned char *id,
+ uint32_t *addr_link)
+{
+ uint32_t x, y;
+
+ x = cc->root;
+ y = ADDR_NULL;
+ while (x != ADDR_NULL) {
+ int r;
+
+ r = memcmp(id, cc->store + x + SESSION_ID_OFF, SESSION_ID_LEN);
+ if (r < 0) {
+ y = x + TREE_LEFT_OFF;
+ x = get_left(cc, x);
+ } else if (r == 0) {
+ if (addr_link != NULL) {
+ *addr_link = y;
+ }
+ return x;
+ } else {
+ y = x + TREE_RIGHT_OFF;
+ x = get_right(cc, x);
+ }
+ }
+ if (addr_link != NULL) {
+ *addr_link = y;
+ }
+ return ADDR_NULL;
+}
+
+/*
+ * For node x, find its replacement upon removal.
+ *
+ * -- If node x has no child, then this returns ADDR_NULL.
+ * -- Otherwise, if node x has a left child, then the replacement is the
+ * rightmost left-descendent.
+ * -- Otherwise, the replacement is the leftmost right-descendent.
+ *
+ * If a node is returned, then '*al' is set to the address of the field
+ * that points to that node.
+ */
+static uint32_t
+find_replacement_node(br_ssl_session_cache_lru *cc, uint32_t x, uint32_t *al)
+{
+ uint32_t y1, y2;
+
+ y1 = get_left(cc, x);
+ if (y1 != ADDR_NULL) {
+ y2 = x + TREE_LEFT_OFF;
+ for (;;) {
+ uint32_t z;
+
+ z = get_right(cc, y1);
+ if (z == ADDR_NULL) {
+ *al = y2;
+ return y1;
+ }
+ y2 = y1 + TREE_RIGHT_OFF;
+ y1 = z;
+ }
+ }
+ y1 = get_right(cc, x);
+ if (y1 != ADDR_NULL) {
+ y2 = x + TREE_RIGHT_OFF;
+ for (;;) {
+ uint32_t z;
+
+ z = get_left(cc, y1);
+ if (z == ADDR_NULL) {
+ *al = y2;
+ return y1;
+ }
+ y2 = y1 + TREE_LEFT_OFF;
+ y1 = z;
+ }
+ }
+ *al = ADDR_NULL;
+ return ADDR_NULL;
+}
+
+static inline void
+set_link(br_ssl_session_cache_lru *cc, uint32_t alx, uint32_t x)
+{
+ if (alx == ADDR_NULL) {
+ cc->root = x;
+ } else {
+ br_enc32be(cc->store + alx, x);
+ }
+}
+
+static void
+remove_node(br_ssl_session_cache_lru *cc, uint32_t x)
+{
+ uint32_t alx, y, aly;
+
+ /*
+ * Find node back and its ancestor link.
+ */
+ find_node(cc, cc->store + x + SESSION_ID_OFF, &alx);
+
+ /*
+ * Find replacement node.
+ */
+ y = find_replacement_node(cc, x, &aly);
+
+ /*
+ * Unlink replacement node.
+ */
+ set_link(cc, aly, ADDR_NULL);
+
+ /*
+ * Link the replacement node in its new place.
+ */
+ set_link(cc, alx, y);
+}
+
+static void
+lru_save(const br_ssl_session_cache_class **ctx,
+ br_ssl_server_context *server_ctx,
+ const br_ssl_session_parameters *params)
+{
+ br_ssl_session_cache_lru *cc;
+ unsigned char id[SESSION_ID_LEN];
+ uint32_t x, alx;
+
+ cc = (br_ssl_session_cache_lru *)ctx;
+
+ /*
+ * If the buffer is too small, we don't record anything. This
+ * test avoids problems in subsequent code.
+ */
+ if (cc->store_len < LRU_ENTRY_LEN) {
+ return;
+ }
+
+ /*
+ * Upon the first save in a session cache instance, we obtain
+ * a random key for our indexing.
+ */
+ if (!cc->init_done) {
+ br_hmac_drbg_generate(&server_ctx->eng.rng,
+ cc->index_key, sizeof cc->index_key);
+ cc->hash = br_hmac_drbg_get_hash(&server_ctx->eng.rng);
+ cc->init_done = 1;
+ }
+ mask_id(cc, params->session_id, id);
+
+ /*
+ * Look for the node in the tree. If the same ID is already used,
+ * then reject it. This is a collision event, which should be
+ * exceedingly rare.
+ * Note: we do NOT record the emplacement here, because the
+ * removal of an entry may change the tree topology.
+ */
+ if (find_node(cc, id, NULL) != ADDR_NULL) {
+ return;
+ }
+
+ /*
+ * Find some room for the new parameters. If the cache is not
+ * full yet, add it to the end of the area and bump the pointer up.
+ * Otherwise, evict the list tail entry. Note that we already
+ * filtered out the case of a ridiculously small buffer that
+ * cannot hold any entry at all; thus, if there is no room for an
+ * extra entry, then the cache cannot be empty.
+ */
+ if (cc->store_ptr > (cc->store_len - LRU_ENTRY_LEN)) {
+ /*
+ * Evict tail. If the buffer has room for a single entry,
+ * then this may also be the head.
+ */
+ x = cc->tail;
+ cc->tail = get_prev(cc, x);
+ if (cc->tail == ADDR_NULL) {
+ cc->head = ADDR_NULL;
+ } else {
+ set_next(cc, cc->tail, ADDR_NULL);
+ }
+
+ /*
+ * Remove the node from the tree.
+ */
+ remove_node(cc, x);
+ } else {
+ /*
+ * Allocate room for new node.
+ */
+ x = cc->store_ptr;
+ cc->store_ptr += LRU_ENTRY_LEN;
+ }
+
+ /*
+ * Find the emplacement for the new node, and link it.
+ */
+ find_node(cc, id, &alx);
+ set_link(cc, alx, x);
+ set_left(cc, x, ADDR_NULL);
+ set_right(cc, x, ADDR_NULL);
+
+ /*
+ * New entry becomes new list head. It may also become the list
+ * tail if the cache was empty at that point.
+ */
+ if (cc->head == ADDR_NULL) {
+ cc->tail = x;
+ } else {
+ set_prev(cc, cc->head, x);
+ }
+ set_prev(cc, x, ADDR_NULL);
+ set_next(cc, x, cc->head);
+ cc->head = x;
+
+ /*
+ * Fill data in the entry.
+ */
+ memcpy(cc->store + x + SESSION_ID_OFF, id, SESSION_ID_LEN);
+ memcpy(cc->store + x + MASTER_SECRET_OFF,
+ params->master_secret, MASTER_SECRET_LEN);
+ br_enc16be(cc->store + x + VERSION_OFF, params->version);
+ br_enc16be(cc->store + x + CIPHER_SUITE_OFF, params->cipher_suite);
+}
+
+static int
+lru_load(const br_ssl_session_cache_class **ctx,
+ br_ssl_server_context *server_ctx,
+ br_ssl_session_parameters *params)
+{
+ br_ssl_session_cache_lru *cc;
+ unsigned char id[SESSION_ID_LEN];
+ uint32_t x;
+
+ (void)server_ctx;
+ cc = (br_ssl_session_cache_lru *)ctx;
+ if (!cc->init_done) {
+ return 0;
+ }
+ mask_id(cc, params->session_id, id);
+ x = find_node(cc, id, NULL);
+ if (x != ADDR_NULL) {
+ params->version = br_dec16be(
+ cc->store + x + VERSION_OFF);
+ params->cipher_suite = br_dec16be(
+ cc->store + x + CIPHER_SUITE_OFF);
+ memcpy(params->master_secret,
+ cc->store + x + MASTER_SECRET_OFF,
+ MASTER_SECRET_LEN);
+ if (x != cc->head) {
+ /*
+ * Found node is not at list head, so move
+ * it to the head.
+ */
+ uint32_t p, n;
+
+ p = get_prev(cc, x);
+ n = get_next(cc, x);
+ set_next(cc, p, n);
+ if (n == ADDR_NULL) {
+ cc->tail = p;
+ } else {
+ set_prev(cc, n, p);
+ }
+ set_prev(cc, cc->head, x);
+ set_next(cc, x, cc->head);
+ set_prev(cc, x, ADDR_NULL);
+ cc->head = x;
+ }
+ return 1;
+ }
+ return 0;
+}
+
+static const br_ssl_session_cache_class lru_class = {
+ sizeof(br_ssl_session_cache_lru),
+ &lru_save,
+ &lru_load
+};
+
+/* see inner.h */
+void
+br_ssl_session_cache_lru_init(br_ssl_session_cache_lru *cc,
+ unsigned char *store, size_t store_len)
+{
+ cc->vtable = &lru_class;
+ cc->store = store;
+ cc->store_len = store_len;
+ cc->store_ptr = 0;
+ cc->init_done = 0;
+ cc->head = ADDR_NULL;
+ cc->tail = ADDR_NULL;
+ cc->root = ADDR_NULL;
+}
--- /dev/null
+/*
+ * 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"
+
+static void
+in_cbc_init(br_sslrec_in_cbc_context *cc,
+ const br_block_cbcdec_class *bc_impl,
+ const void *bc_key, size_t bc_key_len,
+ const br_hash_class *dig_impl,
+ const void *mac_key, size_t mac_key_len, size_t mac_out_len,
+ const void *iv)
+{
+ cc->vtable = &br_sslrec_in_cbc_vtable;
+ cc->seq = 0;
+ bc_impl->init(&cc->bc.vtable, bc_key, bc_key_len);
+ br_hmac_key_init(&cc->mac, dig_impl, mac_key, mac_key_len);
+ cc->mac_len = mac_out_len;
+ if (iv == NULL) {
+ memset(cc->iv, 0, sizeof cc->iv);
+ cc->explicit_IV = 1;
+ } else {
+ memcpy(cc->iv, iv, bc_impl->block_size);
+ cc->explicit_IV = 0;
+ }
+}
+
+static int
+cbc_check_length(const br_sslrec_in_cbc_context *cc, size_t rlen)
+{
+ /*
+ * Plaintext size: at most 16384 bytes
+ * Padding: at most 256 bytes
+ * MAC: mac_len extra bytes
+ * TLS 1.1+: each record has an explicit IV
+ *
+ * Minimum length includes at least one byte of padding, and the
+ * MAC.
+ *
+ * Total length must be a multiple of the block size.
+ */
+ size_t blen;
+ size_t min_len, max_len;
+
+ blen = cc->bc.vtable->block_size;
+ min_len = (blen + cc->mac_len) & ~(blen - 1);
+ max_len = (16384 + 256 + cc->mac_len) & ~(blen - 1);
+ if (cc->explicit_IV) {
+ min_len += blen;
+ max_len += blen;
+ }
+ return min_len <= rlen && rlen <= max_len;
+}
+
+/*
+ * Rotate array buf[] of length 'len' to the left (towards low indices)
+ * by 'num' bytes if ctl is 1; otherwise, leave it unchanged. This is
+ * constant-time. 'num' MUST be lower than 'len'. 'len' MUST be lower
+ * than or equal to 64.
+ */
+static void
+cond_rotate(uint32_t ctl, unsigned char *buf, size_t len, size_t num)
+{
+ unsigned char tmp[64];
+ size_t u, v;
+
+ for (u = 0, v = num; u < len; u ++) {
+ tmp[u] = MUX(ctl, buf[v], buf[u]);
+ if (++ v == len) {
+ v = 0;
+ }
+ }
+ memcpy(buf, tmp, len);
+}
+
+static unsigned char *
+cbc_decrypt(br_sslrec_in_cbc_context *cc,
+ int record_type, unsigned version, void *data, size_t *data_len)
+{
+ /*
+ * We represent all lengths on 32-bit integers, because:
+ * -- SSL record lengths always fit in 32 bits;
+ * -- our constant-time primitives operate on 32-bit integers.
+ */
+ unsigned char *buf;
+ uint32_t u, v, len, blen, min_len, max_len;
+ uint32_t good, pad_len, rot_count, len_withmac, len_nomac;
+ unsigned char tmp1[64], tmp2[64];
+ int i;
+ br_hmac_context hc;
+
+ buf = data;
+ len = *data_len;
+ blen = cc->bc.vtable->block_size;
+
+ /*
+ * Decrypt data, and skip the explicit IV (if applicable). Note
+ * that the total length is supposed to have been verified by
+ * the caller. If there is an explicit IV, then we actually
+ * "decrypt" it using the implicit IV (from previous record),
+ * which is useless but harmless.
+ */
+ cc->bc.vtable->run(&cc->bc.vtable, cc->iv, data, len);
+ if (cc->explicit_IV) {
+ buf += blen;
+ len -= blen;
+ }
+
+ /*
+ * Compute minimum and maximum length of plaintext + MAC. These
+ * lengths can be inferred from the outside: they are not secret.
+ */
+ min_len = (cc->mac_len + 256 < len) ? len - 256 : cc->mac_len;
+ max_len = len - 1;
+
+ /*
+ * Use the last decrypted byte to compute the actual payload
+ * length. Take care not to underflow (we use unsigned types).
+ */
+ pad_len = buf[max_len];
+ good = LE(pad_len, (uint32_t)(max_len - min_len));
+ len = MUX(good, (uint32_t)(max_len - pad_len), min_len);
+
+ /*
+ * Check padding contents: all padding bytes must be equal to
+ * the value of pad_len.
+ */
+ for (u = min_len; u < max_len; u ++) {
+ good &= LT(u, len) | EQ(buf[u], pad_len);
+ }
+
+ /*
+ * Extract the MAC value. This is done in one pass, but results
+ * in a "rotated" MAC value depending on where it actually
+ * occurs. The 'rot_count' value is set to the offset of the
+ * first MAC byte within tmp1[].
+ *
+ * min_len and max_len are also adjusted to the minimum and
+ * maximum lengths of the plaintext alone (without the MAC).
+ */
+ len_withmac = (uint32_t)len;
+ len_nomac = len_withmac - cc->mac_len;
+ min_len -= cc->mac_len;
+ rot_count = 0;
+ memset(tmp1, 0, cc->mac_len);
+ v = 0;
+ for (u = min_len; u < max_len; u ++) {
+ tmp1[v] |= MUX(GE(u, len_nomac) & LT(u, len_withmac),
+ buf[u], 0x00);
+ rot_count = MUX(EQ(u, len_nomac), v, rot_count);
+ if (++ v == cc->mac_len) {
+ v = 0;
+ }
+ }
+ max_len -= cc->mac_len;
+
+ /*
+ * Rotate back the MAC value. The loop below does the constant-time
+ * rotation in time n*log n for a MAC output of length n. We assume
+ * that the MAC output length is no more than 64 bytes, so the
+ * rotation count fits on 6 bits.
+ */
+ for (i = 5; i >= 0; i --) {
+ uint32_t rc;
+
+ rc = (uint32_t)1 << i;
+ cond_rotate(rot_count >> i, tmp1, cc->mac_len, rc);
+ rot_count &= ~rc;
+ }
+
+ /*
+ * Recompute the HMAC value. The input is the concatenation of
+ * the sequence number (8 bytes), the record header (5 bytes),
+ * and the payload.
+ *
+ * At that point, min_len is the minimum plaintext length, but
+ * max_len still includes the MAC length.
+ */
+ br_enc64be(tmp2, cc->seq ++);
+ tmp2[8] = (unsigned char)record_type;
+ br_enc16be(tmp2 + 9, version);
+ br_enc16be(tmp2 + 11, len_nomac);
+ br_hmac_init(&hc, &cc->mac, cc->mac_len);
+ br_hmac_update(&hc, tmp2, 13);
+ br_hmac_outCT(&hc, buf, len_nomac, min_len, max_len, tmp2);
+
+ /*
+ * Compare the extracted and recomputed MAC values.
+ */
+ for (u = 0; u < cc->mac_len; u ++) {
+ good &= EQ0(tmp1[u] ^ tmp2[u]);
+ }
+
+ /*
+ * Check that the plaintext length is valid. The previous
+ * check was on the encrypted length, but the padding may have
+ * turned shorter than expected.
+ *
+ * Once this final test is done, the critical "constant-time"
+ * section ends and we can make conditional jumps again.
+ */
+ good &= LE(len_nomac, 16384);
+
+ if (!good) {
+ return 0;
+ }
+ *data_len = len_nomac;
+ return buf;
+}
+
+/* see bearssl_ssl.h */
+const br_sslrec_in_cbc_class br_sslrec_in_cbc_vtable = {
+ {
+ sizeof(br_sslrec_in_cbc_context),
+ (int (*)(const br_sslrec_in_class *const *, size_t))
+ &cbc_check_length,
+ (unsigned char *(*)(const br_sslrec_in_class **,
+ int, unsigned, void *, size_t *))
+ &cbc_decrypt
+ },
+ (void (*)(const br_sslrec_in_cbc_class **,
+ const br_block_cbcdec_class *, const void *, size_t,
+ const br_hash_class *, const void *, size_t, size_t,
+ const void *))
+ &in_cbc_init
+};
+
+/*
+ * For CBC output:
+ *
+ * -- With TLS 1.1+, there is an explicit IV. Generation method uses
+ * HMAC, computed over the current sequence number, and the current MAC
+ * key. The resulting value is truncated to the size of a block, and
+ * added at the head of the plaintext; it will get encrypted along with
+ * the data. This custom generation mechanism is "safe" under the
+ * assumption that HMAC behaves like a random oracle; since the MAC for
+ * a record is computed over the concatenation of the sequence number,
+ * the record header and the plaintext, the HMAC-for-IV will not collide
+ * with the normal HMAC.
+ *
+ * -- With TLS 1.0, for application data, we want to enforce a 1/n-1
+ * split, as a countermeasure against chosen-plaintext attacks. We thus
+ * need to leave some room in the buffer for that extra record.
+ */
+
+static void
+out_cbc_init(br_sslrec_out_cbc_context *cc,
+ const br_block_cbcenc_class *bc_impl,
+ const void *bc_key, size_t bc_key_len,
+ const br_hash_class *dig_impl,
+ const void *mac_key, size_t mac_key_len, size_t mac_out_len,
+ const void *iv)
+{
+ cc->vtable = &br_sslrec_out_cbc_vtable;
+ cc->seq = 0;
+ bc_impl->init(&cc->bc.vtable, bc_key, bc_key_len);
+ br_hmac_key_init(&cc->mac, dig_impl, mac_key, mac_key_len);
+ cc->mac_len = mac_out_len;
+ if (iv == NULL) {
+ memset(cc->iv, 0, sizeof cc->iv);
+ cc->explicit_IV = 1;
+ } else {
+ memcpy(cc->iv, iv, bc_impl->block_size);
+ cc->explicit_IV = 0;
+ }
+}
+
+static void
+cbc_max_plaintext(const br_sslrec_out_cbc_context *cc,
+ size_t *start, size_t *end)
+{
+ size_t blen, len;
+
+ blen = cc->bc.vtable->block_size;
+ if (cc->explicit_IV) {
+ *start += blen;
+ } else {
+ *start += 4 + ((cc->mac_len + blen + 1) & ~(blen - 1));
+ }
+ len = (*end - *start) & ~(blen - 1);
+ len -= 1 + cc->mac_len;
+ if (len > 16384) {
+ len = 16384;
+ }
+ *end = *start + len;
+}
+
+static unsigned char *
+cbc_encrypt(br_sslrec_out_cbc_context *cc,
+ int record_type, unsigned version, void *data, size_t *data_len)
+{
+ unsigned char *buf, *rbuf;
+ size_t len, blen, plen;
+ unsigned char tmp[13];
+ br_hmac_context hc;
+
+ buf = data;
+ len = *data_len;
+ blen = cc->bc.vtable->block_size;
+
+ /*
+ * If using TLS 1.0, with more than one byte of plaintext, and
+ * the record is application data, then we need to compute
+ * a "split". We do not perform the split on other record types
+ * because it turned out that some existing, deployed
+ * implementations of SSL/TLS do not tolerate the splitting of
+ * some message types (in particular the Finished message).
+ *
+ * If using TLS 1.1+, then there is an explicit IV. We produce
+ * that IV by adding an extra initial plaintext block, whose
+ * value is computed with HMAC over the record sequence number.
+ */
+ if (cc->explicit_IV) {
+ /*
+ * We use here the fact that all the HMAC variants we
+ * support can produce at least 16 bytes, while all the
+ * block ciphers we support have blocks of no more than
+ * 16 bytes. Thus, we can always truncate the HMAC output
+ * down to the block size.
+ */
+ br_enc64be(tmp, cc->seq);
+ br_hmac_init(&hc, &cc->mac, blen);
+ br_hmac_update(&hc, tmp, 8);
+ br_hmac_out(&hc, buf - blen);
+ rbuf = buf - blen - 5;
+ } else {
+ if (len > 1 && record_type == BR_SSL_APPLICATION_DATA) {
+ /*
+ * To do the split, we use a recursive invocation;
+ * since we only give one byte to the inner call,
+ * the recursion stops there.
+ *
+ * We need to compute the exact size of the extra
+ * record, so that the two resulting records end up
+ * being sequential in RAM.
+ *
+ * We use here the fact that cbc_max_plaintext()
+ * adjusted the start offset to leave room for the
+ * initial fragment.
+ */
+ size_t xlen;
+
+ rbuf = buf - 4
+ - ((cc->mac_len + blen + 1) & ~(blen - 1));
+ rbuf[0] = buf[0];
+ xlen = 1;
+ rbuf = cbc_encrypt(cc, record_type,
+ version, rbuf, &xlen);
+ buf ++;
+ len --;
+ } else {
+ rbuf = buf - 5;
+ }
+ }
+
+ /*
+ * Compute MAC.
+ */
+ br_enc64be(tmp, cc->seq ++);
+ tmp[8] = record_type;
+ br_enc16be(tmp + 9, version);
+ br_enc16be(tmp + 11, len);
+ br_hmac_init(&hc, &cc->mac, cc->mac_len);
+ br_hmac_update(&hc, tmp, 13);
+ br_hmac_update(&hc, buf, len);
+ br_hmac_out(&hc, buf + len);
+ len += cc->mac_len;
+
+ /*
+ * Add padding.
+ */
+ plen = blen - (len & (blen - 1));
+ memset(buf + len, (unsigned)plen - 1, plen);
+ len += plen;
+
+ /*
+ * If an explicit IV is used, the corresponding extra block was
+ * already put in place earlier; we just have to account for it
+ * here.
+ */
+ if (cc->explicit_IV) {
+ buf -= blen;
+ len += blen;
+ }
+
+ /*
+ * Encrypt the whole thing. If there is an explicit IV, we also
+ * encrypt it, which is fine (encryption of a uniformly random
+ * block is still a uniformly random block).
+ */
+ cc->bc.vtable->run(&cc->bc.vtable, cc->iv, buf, len);
+
+ /*
+ * Add the header and return.
+ */
+ buf[-5] = record_type;
+ br_enc16be(buf - 4, version);
+ br_enc16be(buf - 2, len);
+ *data_len = (size_t)((buf + len) - rbuf);
+ return rbuf;
+}
+
+/* see bearssl_ssl.h */
+const br_sslrec_out_cbc_class br_sslrec_out_cbc_vtable = {
+ {
+ sizeof(br_sslrec_out_cbc_context),
+ (void (*)(const br_sslrec_out_class *const *,
+ size_t *, size_t *))
+ &cbc_max_plaintext,
+ (unsigned char *(*)(const br_sslrec_out_class **,
+ int, unsigned, void *, size_t *))
+ &cbc_encrypt
+ },
+ (void (*)(const br_sslrec_out_cbc_class **,
+ const br_block_cbcenc_class *, const void *, size_t,
+ const br_hash_class *, const void *, size_t, size_t,
+ const void *))
+ &out_cbc_init
+};
--- /dev/null
+/*
+ * 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"
+
+/*
+ * GCM initialisation. This does everything except setting the vtable,
+ * which depends on whether this is a context for encrypting or for
+ * decrypting.
+ */
+static void
+gen_gcm_init(br_sslrec_gcm_context *cc,
+ const br_block_ctr_class *bc_impl,
+ const void *key, size_t key_len,
+ br_ghash gh_impl,
+ const void *iv)
+{
+ unsigned char tmp[12];
+
+ cc->seq = 0;
+ bc_impl->init(&cc->bc.vtable, key, key_len);
+ cc->gh = gh_impl;
+ memcpy(cc->iv, iv, sizeof cc->iv);
+ memset(cc->h, 0, sizeof cc->h);
+ memset(tmp, 0, sizeof tmp);
+ bc_impl->run(&cc->bc.vtable, tmp, 0, cc->h, sizeof cc->h);
+}
+
+static void
+in_gcm_init(br_sslrec_gcm_context *cc,
+ const br_block_ctr_class *bc_impl,
+ const void *key, size_t key_len,
+ br_ghash gh_impl,
+ const void *iv)
+{
+ cc->vtable.in = &br_sslrec_in_gcm_vtable;
+ gen_gcm_init(cc, bc_impl, key, key_len, gh_impl, iv);
+}
+
+static int
+gcm_check_length(const br_sslrec_gcm_context *cc, size_t rlen)
+{
+ /*
+ * GCM adds a fixed overhead:
+ * 8 bytes for the nonce_explicit (before the ciphertext)
+ * 16 bytes for the authentication tag (after the ciphertext)
+ */
+ (void)cc;
+ return rlen >= 24 && rlen <= (16384 + rlen);
+}
+
+/*
+ * Compute the authentication tag. The value written in 'tag' must still
+ * be CTR-encrypted.
+ */
+static void
+do_tag(br_sslrec_gcm_context *cc,
+ int record_type, unsigned version,
+ void *data, size_t len, void *tag)
+{
+ unsigned char header[13];
+ unsigned char footer[16];
+
+ /*
+ * Compute authentication tag. Three elements must be injected in
+ * sequence, each possibly 0-padded to reach a length multiple
+ * of the block size: the 13-byte header (sequence number, record
+ * type, protocol version, record length), the cipher text, and
+ * the word containing the encodings of the bit lengths of the two
+ * other elements.
+ */
+ br_enc64be(header, cc->seq ++);
+ header[8] = (unsigned char)record_type;
+ br_enc16be(header + 9, version);
+ br_enc16be(header + 11, len);
+ br_enc64be(footer, (uint64_t)(sizeof header) << 3);
+ br_enc64be(footer + 8, (uint64_t)len << 3);
+ memset(tag, 0, 16);
+ cc->gh(tag, cc->h, header, sizeof header);
+ cc->gh(tag, cc->h, data, len);
+ cc->gh(tag, cc->h, footer, sizeof footer);
+}
+
+/*
+ * Do CTR encryption. This also does CTR encryption of a single block at
+ * address 'xortag' with the counter value appropriate for the final
+ * processing of the authentication tag.
+ */
+static void
+do_ctr(br_sslrec_gcm_context *cc, const void *nonce, void *data, size_t len,
+ void *xortag)
+{
+ unsigned char iv[12];
+
+ memcpy(iv, cc->iv, 4);
+ memcpy(iv + 4, nonce, 8);
+ cc->bc.vtable->run(&cc->bc.vtable, iv, 2, data, len);
+ cc->bc.vtable->run(&cc->bc.vtable, iv, 1, xortag, 16);
+}
+
+static unsigned char *
+gcm_decrypt(br_sslrec_gcm_context *cc,
+ int record_type, unsigned version, void *data, size_t *data_len)
+{
+ unsigned char *buf;
+ size_t len, u;
+ uint32_t bad;
+ unsigned char tag[16];
+
+ buf = (unsigned char *)data + 8;
+ len = *data_len - 24;
+ do_tag(cc, record_type, version, buf, len, tag);
+ do_ctr(cc, data, buf, len, tag);
+
+ /*
+ * Compare the computed tag with the value from the record. It
+ * is possibly useless to do a constant-time comparison here,
+ * but it does not hurt.
+ */
+ bad = 0;
+ for (u = 0; u < 16; u ++) {
+ bad |= tag[u] ^ buf[len + u];
+ }
+ if (bad) {
+ return NULL;
+ }
+ *data_len = len;
+ return buf;
+}
+
+/* see bearssl_ssl.h */
+const br_sslrec_in_gcm_class br_sslrec_in_gcm_vtable = {
+ {
+ sizeof(br_sslrec_gcm_context),
+ (int (*)(const br_sslrec_in_class *const *, size_t))
+ &gcm_check_length,
+ (unsigned char *(*)(const br_sslrec_in_class **,
+ int, unsigned, void *, size_t *))
+ &gcm_decrypt
+ },
+ (void (*)(const br_sslrec_in_gcm_class **,
+ const br_block_ctr_class *, const void *, size_t,
+ br_ghash, const void *))
+ &in_gcm_init
+};
+
+static void
+out_gcm_init(br_sslrec_gcm_context *cc,
+ const br_block_ctr_class *bc_impl,
+ const void *key, size_t key_len,
+ br_ghash gh_impl,
+ const void *iv)
+{
+ cc->vtable.out = &br_sslrec_out_gcm_vtable;
+ gen_gcm_init(cc, bc_impl, key, key_len, gh_impl, iv);
+}
+
+static void
+gcm_max_plaintext(const br_sslrec_gcm_context *cc,
+ size_t *start, size_t *end)
+{
+ size_t len;
+
+ (void)cc;
+ *start += 8;
+ len = *end - *start - 16;
+ if (len > 16384) {
+ len = 16384;
+ }
+ *end = *start + len;
+}
+
+static unsigned char *
+gcm_encrypt(br_sslrec_gcm_context *cc,
+ int record_type, unsigned version, void *data, size_t *data_len)
+{
+ unsigned char *buf;
+ size_t u, len;
+ unsigned char tmp[16];
+
+ buf = (unsigned char *)data;
+ len = *data_len;
+ memset(tmp, 0, sizeof tmp);
+ br_enc64be(buf - 8, cc->seq);
+ do_ctr(cc, buf - 8, buf, len, tmp);
+ do_tag(cc, record_type, version, buf, len, buf + len);
+ for (u = 0; u < 16; u ++) {
+ buf[len + u] ^= tmp[u];
+ }
+ len += 24;
+ buf -= 13;
+ buf[0] = (unsigned char)record_type;
+ br_enc16be(buf + 1, version);
+ br_enc16be(buf + 3, len);
+ *data_len = len + 5;
+ return buf;
+}
+
+/* see bearssl_ssl.h */
+const br_sslrec_out_gcm_class br_sslrec_out_gcm_vtable = {
+ {
+ sizeof(br_sslrec_gcm_context),
+ (void (*)(const br_sslrec_out_class *const *,
+ size_t *, size_t *))
+ &gcm_max_plaintext,
+ (unsigned char *(*)(const br_sslrec_out_class **,
+ int, unsigned, void *, size_t *))
+ &gcm_encrypt
+ },
+ (void (*)(const br_sslrec_out_gcm_class **,
+ const br_block_ctr_class *, const void *, size_t,
+ br_ghash, const void *))
+ &out_gcm_init
+};
--- /dev/null
+/*
+ * 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_ssl.h */
+void
+br_ssl_server_zero(br_ssl_server_context *cc)
+{
+ /*
+ * For really standard C, we should explicitly set to NULL all
+ * pointers, and 0 all other fields. However, on all our target
+ * architectures, a direct memset() will work, be faster, and
+ * use a lot less code.
+ */
+ memset(cc, 0, sizeof *cc);
+}
+
+/* see bearssl_ssl.h */
+int
+br_ssl_server_reset(br_ssl_server_context *cc)
+{
+ br_ssl_engine_set_buffer(&cc->eng, NULL, 0, 0);
+ if (!br_ssl_engine_init_rand(&cc->eng)) {
+ return 0;
+ }
+ cc->eng.reneg = 0;
+ br_ssl_engine_hs_reset(&cc->eng,
+ br_ssl_hs_server_init_main, br_ssl_hs_server_run);
+ return br_ssl_engine_last_error(&cc->eng) == BR_ERR_OK;
+}
--- /dev/null
+/*
+ * 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_ssl.h */
+void
+br_ssl_server_init_full_ec(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ unsigned cert_issuer_key_type, const br_ec_private_key *sk)
+{
+ /*
+ * The "full" profile supports all implemented cipher suites.
+ *
+ * Rationale for suite order, from most important to least
+ * important rule:
+ *
+ * -- Don't use 3DES if AES is available.
+ * -- Try to have Forward Secrecy (ECDHE suite) if possible.
+ * -- GCM is better than CBC.
+ * -- AES-128 is preferred over AES-256 (AES-128 is already
+ * strong enough, and AES-256 is 40% more expensive).
+ *
+ * Note that for ECDH suites, the list will be automatically
+ * filtered based on the issuing CA key type.
+ */
+ static const uint16_t suites[] = {
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ BR_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,
+ BR_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,
+ BR_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384,
+ BR_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384,
+ BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
+ BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
+ BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,
+ BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,
+ BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
+ BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
+ BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
+ BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
+ BR_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ BR_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ BR_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA
+ };
+
+ /*
+ * 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;
+
+ /*
+ * Reset server context and set supported versions from TLS-1.0
+ * to TLS-1.2 (inclusive).
+ */
+ br_ssl_server_zero(cc);
+ br_ssl_engine_set_versions(&cc->eng, BR_TLS10, BR_TLS12);
+
+ /*
+ * Set suites and elliptic curve implementation (for ECDHE).
+ */
+ br_ssl_engine_set_suites(&cc->eng, suites,
+ (sizeof suites) / (sizeof suites[0]));
+ br_ssl_engine_set_ec(&cc->eng, &br_ec_prime_i31);
+
+ /*
+ * Set the "server policy": handler for the certificate chain
+ * and private key operations.
+ */
+ br_ssl_server_set_single_ec(cc, chain, chain_len, sk,
+ BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN,
+ cert_issuer_key_type,
+ &br_ec_prime_i31, br_ecdsa_i31_sign_asn1);
+
+ /*
+ * Set supported hash functions.
+ */
+ for (id = br_md5_ID; id <= br_sha512_ID; id ++) {
+ const br_hash_class *hc;
+
+ hc = hashes[id - 1];
+ br_ssl_engine_set_hash(&cc->eng, id, hc);
+ }
+
+ /*
+ * Set the PRF implementations.
+ */
+ br_ssl_engine_set_prf10(&cc->eng, &br_tls10_prf);
+ br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf);
+ br_ssl_engine_set_prf_sha384(&cc->eng, &br_tls12_sha384_prf);
+
+ /*
+ * Symmetric encryption. We use the "constant-time"
+ * implementations, which are the safest.
+ *
+ * On architectures detected as "64-bit", use the 64-bit
+ * versions (aes_ct64, ghash_ctmul64).
+ */
+#if BR_64
+ br_ssl_engine_set_aes_cbc(&cc->eng,
+ &br_aes_ct64_cbcenc_vtable,
+ &br_aes_ct64_cbcdec_vtable);
+ br_ssl_engine_set_aes_ctr(&cc->eng,
+ &br_aes_ct64_ctr_vtable);
+ br_ssl_engine_set_ghash(&cc->eng,
+ &br_ghash_ctmul64);
+#else
+ br_ssl_engine_set_aes_cbc(&cc->eng,
+ &br_aes_ct_cbcenc_vtable,
+ &br_aes_ct_cbcdec_vtable);
+ br_ssl_engine_set_aes_ctr(&cc->eng,
+ &br_aes_ct_ctr_vtable);
+ br_ssl_engine_set_ghash(&cc->eng,
+ &br_ghash_ctmul);
+#endif
+ br_ssl_engine_set_des_cbc(&cc->eng,
+ &br_des_ct_cbcenc_vtable,
+ &br_des_ct_cbcdec_vtable);
+
+ /*
+ * Set the SSL record engines (CBC, GCM).
+ */
+ br_ssl_engine_set_cbc(&cc->eng,
+ &br_sslrec_in_cbc_vtable,
+ &br_sslrec_out_cbc_vtable);
+ br_ssl_engine_set_gcm(&cc->eng,
+ &br_sslrec_in_gcm_vtable,
+ &br_sslrec_out_gcm_vtable);
+}
--- /dev/null
+/*
+ * 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_ssl.h */
+void
+br_ssl_server_init_full_rsa(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_rsa_private_key *sk)
+{
+ /*
+ * The "full" profile supports all implemented cipher suites.
+ *
+ * Rationale for suite order, from most important to least
+ * important rule:
+ *
+ * -- Don't use 3DES if AES is available.
+ * -- Try to have Forward Secrecy (ECDHE suite) if possible.
+ * -- GCM is better than CBC.
+ * -- AES-128 is preferred over AES-256 (AES-128 is already
+ * strong enough, and AES-256 is 40% more expensive).
+ */
+ static const uint16_t suites[] = {
+ BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ BR_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+ BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
+ BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ BR_TLS_RSA_WITH_AES_128_GCM_SHA256,
+ BR_TLS_RSA_WITH_AES_256_GCM_SHA384,
+ BR_TLS_RSA_WITH_AES_128_CBC_SHA256,
+ BR_TLS_RSA_WITH_AES_256_CBC_SHA256,
+ BR_TLS_RSA_WITH_AES_128_CBC_SHA,
+ BR_TLS_RSA_WITH_AES_256_CBC_SHA,
+ BR_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ BR_TLS_RSA_WITH_3DES_EDE_CBC_SHA
+ };
+
+ /*
+ * 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;
+
+ /*
+ * Reset server context and set supported versions from TLS-1.0
+ * to TLS-1.2 (inclusive).
+ */
+ br_ssl_server_zero(cc);
+ br_ssl_engine_set_versions(&cc->eng, BR_TLS10, BR_TLS12);
+
+ /*
+ * Set suites and elliptic curve implementation (for ECDHE).
+ */
+ br_ssl_engine_set_suites(&cc->eng, suites,
+ (sizeof suites) / (sizeof suites[0]));
+ br_ssl_engine_set_ec(&cc->eng, &br_ec_prime_i31);
+
+ /*
+ * Set the "server policy": handler for the certificate chain
+ * and private key operations.
+ */
+ br_ssl_server_set_single_rsa(cc, chain, chain_len, sk,
+ BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN,
+ br_rsa_i31_private, br_rsa_i31_pkcs1_sign);
+
+ /*
+ * Set supported hash functions.
+ */
+ for (id = br_md5_ID; id <= br_sha512_ID; id ++) {
+ const br_hash_class *hc;
+
+ hc = hashes[id - 1];
+ br_ssl_engine_set_hash(&cc->eng, id, hc);
+ }
+
+ /*
+ * Set the PRF implementations.
+ */
+ br_ssl_engine_set_prf10(&cc->eng, &br_tls10_prf);
+ br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf);
+ br_ssl_engine_set_prf_sha384(&cc->eng, &br_tls12_sha384_prf);
+
+ /*
+ * Symmetric encryption. We use the "constant-time"
+ * implementations, which are the safest.
+ *
+ * On architectures detected as "64-bit", use the 64-bit
+ * versions (aes_ct64, ghash_ctmul64).
+ */
+#if BR_64
+ br_ssl_engine_set_aes_cbc(&cc->eng,
+ &br_aes_ct64_cbcenc_vtable,
+ &br_aes_ct64_cbcdec_vtable);
+ br_ssl_engine_set_aes_ctr(&cc->eng,
+ &br_aes_ct64_ctr_vtable);
+ br_ssl_engine_set_ghash(&cc->eng,
+ &br_ghash_ctmul64);
+#else
+ br_ssl_engine_set_aes_cbc(&cc->eng,
+ &br_aes_ct_cbcenc_vtable,
+ &br_aes_ct_cbcdec_vtable);
+ br_ssl_engine_set_aes_ctr(&cc->eng,
+ &br_aes_ct_ctr_vtable);
+ br_ssl_engine_set_ghash(&cc->eng,
+ &br_ghash_ctmul);
+#endif
+ br_ssl_engine_set_des_cbc(&cc->eng,
+ &br_des_ct_cbcenc_vtable,
+ &br_des_ct_cbcdec_vtable);
+
+ /*
+ * Set the SSL record engines (CBC, GCM).
+ */
+ br_ssl_engine_set_cbc(&cc->eng,
+ &br_sslrec_in_cbc_vtable,
+ &br_sslrec_out_cbc_vtable);
+ br_ssl_engine_set_gcm(&cc->eng,
+ &br_sslrec_in_gcm_vtable,
+ &br_sslrec_out_gcm_vtable);
+}
--- /dev/null
+/*
+ * 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_ssl.h */
+void
+br_ssl_server_init_mine2g(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_rsa_private_key *sk)
+{
+ static const uint16_t suites[] = {
+ BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+ };
+
+ /*
+ * Reset server context and set supported versions to TLS-1.2 (only).
+ */
+ br_ssl_server_zero(cc);
+ br_ssl_engine_set_versions(&cc->eng, BR_TLS12, BR_TLS12);
+
+ /*
+ * Set suites and elliptic curve implementation (for ECDHE).
+ */
+ br_ssl_engine_set_suites(&cc->eng, suites,
+ (sizeof suites) / (sizeof suites[0]));
+ br_ssl_engine_set_ec(&cc->eng, &br_ec_prime_i31);
+
+ /*
+ * Set the "server policy": handler for the certificate chain
+ * and private key operations.
+ */
+ br_ssl_server_set_single_rsa(cc, chain, chain_len, sk,
+ BR_KEYTYPE_SIGN, 0, br_rsa_i31_pkcs1_sign);
+
+ /*
+ * Set supported hash functions.
+ */
+ br_ssl_engine_set_hash(&cc->eng, br_sha256_ID, &br_sha256_vtable);
+
+ /*
+ * Set the PRF implementations.
+ */
+ br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf);
+
+ /*
+ * Symmetric encryption. We use the "constant-time"
+ * implementations, which are the safest.
+ *
+ * On architectures detected as "64-bit", use the 64-bit
+ * versions (aes_ct64, ghash_ctmul64).
+ */
+#if BR_64
+ br_ssl_engine_set_aes_ctr(&cc->eng,
+ &br_aes_ct64_ctr_vtable);
+ br_ssl_engine_set_ghash(&cc->eng,
+ &br_ghash_ctmul64);
+#else
+ br_ssl_engine_set_aes_ctr(&cc->eng,
+ &br_aes_ct_ctr_vtable);
+ br_ssl_engine_set_ghash(&cc->eng,
+ &br_ghash_ctmul);
+#endif
+
+ /*
+ * Set the SSL record engines (CBC, GCM).
+ */
+ br_ssl_engine_set_gcm(&cc->eng,
+ &br_sslrec_in_gcm_vtable,
+ &br_sslrec_out_gcm_vtable);
+}
--- /dev/null
+/*
+ * 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_ssl.h */
+void
+br_ssl_server_init_minf2g(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_ec_private_key *sk)
+{
+ static const uint16_t suites[] = {
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
+ };
+
+ /*
+ * Reset server context and set supported versions to TLS-1.2 (only).
+ */
+ br_ssl_server_zero(cc);
+ br_ssl_engine_set_versions(&cc->eng, BR_TLS12, BR_TLS12);
+
+ /*
+ * Set suites and elliptic curve implementation (for ECDHE).
+ */
+ br_ssl_engine_set_suites(&cc->eng, suites,
+ (sizeof suites) / (sizeof suites[0]));
+ br_ssl_engine_set_ec(&cc->eng, &br_ec_prime_i31);
+
+ /*
+ * Set the "server policy": handler for the certificate chain
+ * and private key operations.
+ */
+ br_ssl_server_set_single_ec(cc, chain, chain_len, sk,
+ BR_KEYTYPE_SIGN, 0, &br_ec_prime_i31, br_ecdsa_i31_sign_asn1);
+
+ /*
+ * Set supported hash functions.
+ */
+ br_ssl_engine_set_hash(&cc->eng, br_sha256_ID, &br_sha256_vtable);
+
+ /*
+ * Set the PRF implementations.
+ */
+ br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf);
+
+ /*
+ * Symmetric encryption. We use the "constant-time"
+ * implementations, which are the safest.
+ *
+ * On architectures detected as "64-bit", use the 64-bit
+ * versions (aes_ct64, ghash_ctmul64).
+ */
+#if BR_64
+ br_ssl_engine_set_aes_ctr(&cc->eng,
+ &br_aes_ct64_ctr_vtable);
+ br_ssl_engine_set_ghash(&cc->eng,
+ &br_ghash_ctmul64);
+#else
+ br_ssl_engine_set_aes_ctr(&cc->eng,
+ &br_aes_ct_ctr_vtable);
+ br_ssl_engine_set_ghash(&cc->eng,
+ &br_ghash_ctmul);
+#endif
+
+ /*
+ * Set the SSL record engines (CBC, GCM).
+ */
+ br_ssl_engine_set_gcm(&cc->eng,
+ &br_sslrec_in_gcm_vtable,
+ &br_sslrec_out_gcm_vtable);
+}
--- /dev/null
+/*
+ * 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_ssl.h */
+void
+br_ssl_server_init_minr2g(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_rsa_private_key *sk)
+{
+ static const uint16_t suites[] = {
+ BR_TLS_RSA_WITH_AES_128_GCM_SHA256
+ };
+
+ /*
+ * Reset server context and set supported versions to TLS-1.2 (only).
+ */
+ br_ssl_server_zero(cc);
+ br_ssl_engine_set_versions(&cc->eng, BR_TLS12, BR_TLS12);
+
+ /*
+ * Set suites.
+ */
+ br_ssl_engine_set_suites(&cc->eng, suites,
+ (sizeof suites) / (sizeof suites[0]));
+
+ /*
+ * Set the "server policy": handler for the certificate chain
+ * and private key operations.
+ */
+ br_ssl_server_set_single_rsa(cc, chain, chain_len, sk,
+ BR_KEYTYPE_KEYX, br_rsa_i31_private, 0);
+
+ /*
+ * Set supported hash functions.
+ */
+ br_ssl_engine_set_hash(&cc->eng, br_sha256_ID, &br_sha256_vtable);
+
+ /*
+ * Set the PRF implementations.
+ */
+ br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf);
+
+ /*
+ * Symmetric encryption. We use the "constant-time"
+ * implementations, which are the safest.
+ *
+ * On architectures detected as "64-bit", use the 64-bit
+ * versions (aes_ct64, ghash_ctmul64).
+ */
+#if BR_64
+ br_ssl_engine_set_aes_ctr(&cc->eng,
+ &br_aes_ct64_ctr_vtable);
+ br_ssl_engine_set_ghash(&cc->eng,
+ &br_ghash_ctmul64);
+#else
+ br_ssl_engine_set_aes_ctr(&cc->eng,
+ &br_aes_ct_ctr_vtable);
+ br_ssl_engine_set_ghash(&cc->eng,
+ &br_ghash_ctmul);
+#endif
+
+ /*
+ * Set the SSL record engines (CBC, GCM).
+ */
+ br_ssl_engine_set_gcm(&cc->eng,
+ &br_sslrec_in_gcm_vtable,
+ &br_sslrec_out_gcm_vtable);
+}
--- /dev/null
+/*
+ * 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_ssl.h */
+void
+br_ssl_server_init_minu2g(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_ec_private_key *sk)
+{
+ static const uint16_t suites[] = {
+ BR_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
+ };
+
+ /*
+ * Reset server context and set supported versions to TLS-1.2 (only).
+ */
+ br_ssl_server_zero(cc);
+ br_ssl_engine_set_versions(&cc->eng, BR_TLS12, BR_TLS12);
+
+ /*
+ * Set suites.
+ */
+ br_ssl_engine_set_suites(&cc->eng, suites,
+ (sizeof suites) / (sizeof suites[0]));
+
+ /*
+ * Set the "server policy": handler for the certificate chain
+ * and private key operations.
+ */
+ br_ssl_server_set_single_ec(cc, chain, chain_len, sk,
+ BR_KEYTYPE_KEYX, BR_KEYTYPE_RSA, &br_ec_prime_i31, 0);
+
+ /*
+ * Set supported hash functions.
+ */
+ br_ssl_engine_set_hash(&cc->eng, br_sha256_ID, &br_sha256_vtable);
+
+ /*
+ * Set the PRF implementations.
+ */
+ br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf);
+
+ /*
+ * Symmetric encryption. We use the "constant-time"
+ * implementations, which are the safest.
+ *
+ * On architectures detected as "64-bit", use the 64-bit
+ * versions (aes_ct64, ghash_ctmul64).
+ */
+#if BR_64
+ br_ssl_engine_set_aes_ctr(&cc->eng,
+ &br_aes_ct64_ctr_vtable);
+ br_ssl_engine_set_ghash(&cc->eng,
+ &br_ghash_ctmul64);
+#else
+ br_ssl_engine_set_aes_ctr(&cc->eng,
+ &br_aes_ct_ctr_vtable);
+ br_ssl_engine_set_ghash(&cc->eng,
+ &br_ghash_ctmul);
+#endif
+
+ /*
+ * Set the SSL record engines (CBC, GCM).
+ */
+ br_ssl_engine_set_gcm(&cc->eng,
+ &br_sslrec_in_gcm_vtable,
+ &br_sslrec_out_gcm_vtable);
+}
--- /dev/null
+/*
+ * 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_ssl.h */
+void
+br_ssl_server_init_minv2g(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_ec_private_key *sk)
+{
+ static const uint16_t suites[] = {
+ BR_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
+ };
+
+ /*
+ * Reset server context and set supported versions to TLS-1.2 (only).
+ */
+ br_ssl_server_zero(cc);
+ br_ssl_engine_set_versions(&cc->eng, BR_TLS12, BR_TLS12);
+
+ /*
+ * Set suites.
+ */
+ br_ssl_engine_set_suites(&cc->eng, suites,
+ (sizeof suites) / (sizeof suites[0]));
+
+ /*
+ * Set the "server policy": handler for the certificate chain
+ * and private key operations.
+ */
+ br_ssl_server_set_single_ec(cc, chain, chain_len, sk,
+ BR_KEYTYPE_KEYX, BR_KEYTYPE_EC, &br_ec_prime_i31, 0);
+
+ /*
+ * Set supported hash functions.
+ */
+ br_ssl_engine_set_hash(&cc->eng, br_sha256_ID, &br_sha256_vtable);
+
+ /*
+ * Set the PRF implementations.
+ */
+ br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf);
+
+ /*
+ * Symmetric encryption. We use the "constant-time"
+ * implementations, which are the safest.
+ *
+ * On architectures detected as "64-bit", use the 64-bit
+ * versions (aes_ct64, ghash_ctmul64).
+ */
+#if BR_64
+ br_ssl_engine_set_aes_ctr(&cc->eng,
+ &br_aes_ct64_ctr_vtable);
+ br_ssl_engine_set_ghash(&cc->eng,
+ &br_ghash_ctmul64);
+#else
+ br_ssl_engine_set_aes_ctr(&cc->eng,
+ &br_aes_ct_ctr_vtable);
+ br_ssl_engine_set_ghash(&cc->eng,
+ &br_ghash_ctmul);
+#endif
+
+ /*
+ * Set the SSL record engines (CBC, GCM).
+ */
+ br_ssl_engine_set_gcm(&cc->eng,
+ &br_sslrec_in_gcm_vtable,
+ &br_sslrec_out_gcm_vtable);
+}
--- /dev/null
+/*
+ * 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"
+
+static int
+se_choose(const br_ssl_server_policy_class **pctx,
+ const br_ssl_server_context *cc,
+ br_ssl_server_choices *choices)
+{
+ br_ssl_server_policy_ec_context *pc;
+ const br_suite_translated *st;
+ size_t u, st_num;
+ int hash_id;
+
+ pc = (br_ssl_server_policy_ec_context *)pctx;
+ st = br_ssl_server_get_client_suites(cc, &st_num);
+ hash_id = br_ssl_choose_hash(br_ssl_server_get_client_hashes(cc));
+ choices->chain = pc->chain;
+ choices->chain_len = pc->chain_len;
+ for (u = 0; u < st_num; u ++) {
+ unsigned tt;
+
+ tt = st[u][1];
+ switch (tt >> 12) {
+ case BR_SSLKEYX_ECDH_RSA:
+ if ((pc->allowed_usages & BR_KEYTYPE_KEYX) != 0
+ && pc->cert_issuer_key_type == BR_KEYTYPE_RSA)
+ {
+ choices->cipher_suite = st[u][0];
+ return 1;
+ }
+ break;
+ case BR_SSLKEYX_ECDH_ECDSA:
+ if ((pc->allowed_usages & BR_KEYTYPE_KEYX) != 0
+ && pc->cert_issuer_key_type == BR_KEYTYPE_EC)
+ {
+ choices->cipher_suite = st[u][0];
+ return 1;
+ }
+ break;
+ case BR_SSLKEYX_ECDHE_ECDSA:
+ if ((pc->allowed_usages & BR_KEYTYPE_SIGN) != 0
+ && hash_id != 0)
+ {
+ choices->cipher_suite = st[u][0];
+ choices->hash_id = hash_id;
+ return 1;
+ }
+ break;
+ }
+ }
+ return 0;
+}
+
+static uint32_t
+se_do_keyx(const br_ssl_server_policy_class **pctx,
+ unsigned char *data, size_t len)
+{
+ br_ssl_server_policy_ec_context *pc;
+
+ pc = (br_ssl_server_policy_ec_context *)pctx;
+ return pc->iec->mul(data, len, pc->sk->x, pc->sk->xlen, pc->sk->curve);
+}
+
+static size_t
+se_do_sign(const br_ssl_server_policy_class **pctx,
+ int hash_id, size_t hv_len, unsigned char *data, size_t len)
+{
+ br_ssl_server_policy_ec_context *pc;
+ unsigned char hv[64];
+ const br_hash_class *hc;
+
+ pc = (br_ssl_server_policy_ec_context *)pctx;
+ hc = br_multihash_getimpl(pc->mhash, hash_id);
+ if (hc == NULL) {
+ return 0;
+ }
+ memcpy(hv, data, hv_len);
+ if (len < 139) {
+ return 0;
+ }
+ return pc->iecdsa(pc->iec, hc, hv, pc->sk, data);
+}
+
+static const br_ssl_server_policy_class se_policy_vtable = {
+ sizeof(br_ssl_server_policy_ec_context),
+ se_choose,
+ se_do_keyx,
+ se_do_sign
+};
+
+/* see bearssl_ssl.h */
+void
+br_ssl_server_set_single_ec(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_ec_private_key *sk, unsigned allowed_usages,
+ unsigned cert_issuer_key_type,
+ const br_ec_impl *iec, br_ecdsa_sign iecdsa)
+{
+ cc->chain_handler.single_ec.vtable = &se_policy_vtable;
+ cc->chain_handler.single_ec.chain = chain;
+ cc->chain_handler.single_ec.chain_len = chain_len;
+ cc->chain_handler.single_ec.sk = sk;
+ cc->chain_handler.single_ec.allowed_usages = allowed_usages;
+ cc->chain_handler.single_ec.cert_issuer_key_type = cert_issuer_key_type;
+ cc->chain_handler.single_ec.mhash = &cc->eng.mhash;
+ cc->chain_handler.single_ec.iec = iec;
+ cc->chain_handler.single_ec.iecdsa = iecdsa;
+ cc->policy_vtable = &cc->chain_handler.single_ec.vtable;
+}
--- /dev/null
+/*
+ * 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"
+
+static int
+sr_choose(const br_ssl_server_policy_class **pctx,
+ const br_ssl_server_context *cc,
+ br_ssl_server_choices *choices)
+{
+ br_ssl_server_policy_rsa_context *pc;
+ const br_suite_translated *st;
+ size_t u, st_num;
+ int hash_id;
+
+ pc = (br_ssl_server_policy_rsa_context *)pctx;
+ st = br_ssl_server_get_client_suites(cc, &st_num);
+ hash_id = br_ssl_choose_hash(br_ssl_server_get_client_hashes(cc));
+ choices->chain = pc->chain;
+ choices->chain_len = pc->chain_len;
+ for (u = 0; u < st_num; u ++) {
+ unsigned tt;
+
+ tt = st[u][1];
+ switch (tt >> 12) {
+ case BR_SSLKEYX_RSA:
+ if ((pc->allowed_usages & BR_KEYTYPE_KEYX) != 0) {
+ choices->cipher_suite = st[u][0];
+ return 1;
+ }
+ break;
+ case BR_SSLKEYX_ECDHE_RSA:
+ if ((pc->allowed_usages & BR_KEYTYPE_SIGN) != 0
+ && hash_id != 0)
+ {
+ choices->cipher_suite = st[u][0];
+ choices->hash_id = hash_id;
+ return 1;
+ }
+ break;
+ }
+ }
+ return 0;
+}
+
+static uint32_t
+sr_do_keyx(const br_ssl_server_policy_class **pctx,
+ unsigned char *data, size_t len)
+{
+ br_ssl_server_policy_rsa_context *pc;
+
+ pc = (br_ssl_server_policy_rsa_context *)pctx;
+ return br_rsa_ssl_decrypt(pc->irsacore, pc->sk, data, len);
+}
+
+/*
+ * OID for hash functions in RSA signatures.
+ */
+static const unsigned char HASH_OID_SHA1[] = {
+ 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A
+};
+
+static const unsigned char HASH_OID_SHA224[] = {
+ 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04
+};
+
+static const unsigned char HASH_OID_SHA256[] = {
+ 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01
+};
+
+static const unsigned char HASH_OID_SHA384[] = {
+ 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02
+};
+
+static const unsigned char HASH_OID_SHA512[] = {
+ 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03
+};
+
+static const unsigned char *HASH_OID[] = {
+ HASH_OID_SHA1,
+ HASH_OID_SHA224,
+ HASH_OID_SHA256,
+ HASH_OID_SHA384,
+ HASH_OID_SHA512
+};
+
+static size_t
+sr_do_sign(const br_ssl_server_policy_class **pctx,
+ int hash_id, size_t hv_len, unsigned char *data, size_t len)
+{
+ br_ssl_server_policy_rsa_context *pc;
+ unsigned char hv[64];
+ size_t sig_len;
+ const unsigned char *hash_oid;
+
+ pc = (br_ssl_server_policy_rsa_context *)pctx;
+ memcpy(hv, data, hv_len);
+ if (hash_id == 0) {
+ hash_oid = NULL;
+ } else if (hash_id >= 2 && hash_id <= 6) {
+ hash_oid = HASH_OID[hash_id - 2];
+ } else {
+ return 0;
+ }
+ sig_len = (pc->sk->n_bitlen + 7) >> 3;
+ if (len < sig_len) {
+ return 0;
+ }
+ return pc->irsasign(hash_oid, hv, hv_len, pc->sk, data) ? sig_len : 0;
+}
+
+static const br_ssl_server_policy_class sr_policy_vtable = {
+ sizeof(br_ssl_server_policy_rsa_context),
+ sr_choose,
+ sr_do_keyx,
+ sr_do_sign
+};
+
+/* see bearssl_ssl.h */
+void
+br_ssl_server_set_single_rsa(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_rsa_private_key *sk, unsigned allowed_usages,
+ br_rsa_private irsacore, br_rsa_pkcs1_sign irsasign)
+{
+ cc->chain_handler.single_rsa.vtable = &sr_policy_vtable;
+ cc->chain_handler.single_rsa.chain = chain;
+ cc->chain_handler.single_rsa.chain_len = chain_len;
+ cc->chain_handler.single_rsa.sk = sk;
+ cc->chain_handler.single_rsa.allowed_usages = allowed_usages;
+ cc->chain_handler.single_rsa.irsacore = irsacore;
+ cc->chain_handler.single_rsa.irsasign = irsasign;
+ cc->policy_vtable = &cc->chain_handler.single_rsa.vtable;
+}
--- /dev/null
+/*
+ * 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_block.h */
+void
+br_aes_big_cbcdec_init(br_aes_big_cbcdec_keys *ctx,
+ const void *key, size_t len)
+{
+ ctx->vtable = &br_aes_big_cbcdec_vtable;
+ ctx->num_rounds = br_aes_big_keysched_inv(ctx->skey, key, len);
+}
+
+/* see bearssl_block.h */
+void
+br_aes_big_cbcdec_run(const br_aes_big_cbcdec_keys *ctx,
+ void *iv, void *data, size_t len)
+{
+ unsigned char *buf, *ivbuf;
+
+ ivbuf = iv;
+ buf = data;
+ while (len > 0) {
+ unsigned char tmp[16];
+ int i;
+
+ memcpy(tmp, buf, 16);
+ br_aes_big_decrypt(ctx->num_rounds, ctx->skey, buf);
+ for (i = 0; i < 16; i ++) {
+ buf[i] ^= ivbuf[i];
+ }
+ memcpy(ivbuf, tmp, 16);
+ buf += 16;
+ len -= 16;
+ }
+}
+
+/* see bearssl_block.h */
+const br_block_cbcdec_class br_aes_big_cbcdec_vtable = {
+ sizeof(br_aes_big_cbcdec_keys),
+ 16,
+ 4,
+ (void (*)(const br_block_cbcdec_class **, const void *, size_t))
+ &br_aes_big_cbcdec_init,
+ (void (*)(const br_block_cbcdec_class *const *, void *, void *, size_t))
+ &br_aes_big_cbcdec_run
+};
--- /dev/null
+/*
+ * 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_block.h */
+void
+br_aes_big_cbcenc_init(br_aes_big_cbcenc_keys *ctx,
+ const void *key, size_t len)
+{
+ ctx->vtable = &br_aes_big_cbcenc_vtable;
+ ctx->num_rounds = br_aes_keysched(ctx->skey, key, len);
+}
+
+/* see bearssl_block.h */
+void
+br_aes_big_cbcenc_run(const br_aes_big_cbcenc_keys *ctx,
+ void *iv, void *data, size_t len)
+{
+ unsigned char *buf, *ivbuf;
+
+ ivbuf = iv;
+ buf = data;
+ while (len > 0) {
+ int i;
+
+ for (i = 0; i < 16; i ++) {
+ buf[i] ^= ivbuf[i];
+ }
+ br_aes_big_encrypt(ctx->num_rounds, ctx->skey, buf);
+ memcpy(ivbuf, buf, 16);
+ buf += 16;
+ len -= 16;
+ }
+}
+
+/* see bearssl_block.h */
+const br_block_cbcenc_class br_aes_big_cbcenc_vtable = {
+ sizeof(br_aes_big_cbcenc_keys),
+ 16,
+ 4,
+ (void (*)(const br_block_cbcenc_class **, const void *, size_t))
+ &br_aes_big_cbcenc_init,
+ (void (*)(const br_block_cbcenc_class *const *, void *, void *, size_t))
+ &br_aes_big_cbcenc_run
+};
--- /dev/null
+/*
+ * 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_block.h */
+void
+br_aes_big_ctr_init(br_aes_big_ctr_keys *ctx,
+ const void *key, size_t len)
+{
+ ctx->vtable = &br_aes_big_ctr_vtable;
+ ctx->num_rounds = br_aes_keysched(ctx->skey, key, len);
+}
+
+static void
+xorbuf(void *dst, const void *src, size_t len)
+{
+ unsigned char *d;
+ const unsigned char *s;
+
+ d = dst;
+ s = src;
+ while (len -- > 0) {
+ *d ++ ^= *s ++;
+ }
+}
+
+/* see bearssl_block.h */
+uint32_t
+br_aes_big_ctr_run(const br_aes_big_ctr_keys *ctx,
+ const void *iv, uint32_t cc, void *data, size_t len)
+{
+ unsigned char *buf;
+
+ buf = data;
+ while (len > 0) {
+ unsigned char tmp[16];
+
+ memcpy(tmp, iv, 12);
+ br_enc32be(tmp + 12, cc ++);
+ br_aes_big_encrypt(ctx->num_rounds, ctx->skey, tmp);
+ if (len <= 16) {
+ xorbuf(buf, tmp, len);
+ break;
+ }
+ xorbuf(buf, tmp, 16);
+ buf += 16;
+ len -= 16;
+ }
+ return cc;
+}
+
+/* see bearssl_block.h */
+const br_block_ctr_class br_aes_big_ctr_vtable = {
+ sizeof(br_aes_big_ctr_keys),
+ 16,
+ 4,
+ (void (*)(const br_block_ctr_class **, const void *, size_t))
+ &br_aes_big_ctr_init,
+ (uint32_t (*)(const br_block_ctr_class *const *,
+ const void *, uint32_t, void *, size_t))
+ &br_aes_big_ctr_run
+};
--- /dev/null
+/*
+ * 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"
+
+/*
+ * Inverse S-box (used in key schedule for decryption).
+ */
+static const unsigned char iS[] = {
+ 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E,
+ 0x81, 0xF3, 0xD7, 0xFB, 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87,
+ 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, 0x54, 0x7B, 0x94, 0x32,
+ 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
+ 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49,
+ 0x6D, 0x8B, 0xD1, 0x25, 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16,
+ 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, 0x6C, 0x70, 0x48, 0x50,
+ 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
+ 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05,
+ 0xB8, 0xB3, 0x45, 0x06, 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02,
+ 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, 0x3A, 0x91, 0x11, 0x41,
+ 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
+ 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8,
+ 0x1C, 0x75, 0xDF, 0x6E, 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89,
+ 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, 0xFC, 0x56, 0x3E, 0x4B,
+ 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
+ 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59,
+ 0x27, 0x80, 0xEC, 0x5F, 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D,
+ 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, 0xA0, 0xE0, 0x3B, 0x4D,
+ 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
+ 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63,
+ 0x55, 0x21, 0x0C, 0x7D
+};
+
+static const uint32_t iSsm0[] = {
+ 0x51F4A750, 0x7E416553, 0x1A17A4C3, 0x3A275E96, 0x3BAB6BCB, 0x1F9D45F1,
+ 0xACFA58AB, 0x4BE30393, 0x2030FA55, 0xAD766DF6, 0x88CC7691, 0xF5024C25,
+ 0x4FE5D7FC, 0xC52ACBD7, 0x26354480, 0xB562A38F, 0xDEB15A49, 0x25BA1B67,
+ 0x45EA0E98, 0x5DFEC0E1, 0xC32F7502, 0x814CF012, 0x8D4697A3, 0x6BD3F9C6,
+ 0x038F5FE7, 0x15929C95, 0xBF6D7AEB, 0x955259DA, 0xD4BE832D, 0x587421D3,
+ 0x49E06929, 0x8EC9C844, 0x75C2896A, 0xF48E7978, 0x99583E6B, 0x27B971DD,
+ 0xBEE14FB6, 0xF088AD17, 0xC920AC66, 0x7DCE3AB4, 0x63DF4A18, 0xE51A3182,
+ 0x97513360, 0x62537F45, 0xB16477E0, 0xBB6BAE84, 0xFE81A01C, 0xF9082B94,
+ 0x70486858, 0x8F45FD19, 0x94DE6C87, 0x527BF8B7, 0xAB73D323, 0x724B02E2,
+ 0xE31F8F57, 0x6655AB2A, 0xB2EB2807, 0x2FB5C203, 0x86C57B9A, 0xD33708A5,
+ 0x302887F2, 0x23BFA5B2, 0x02036ABA, 0xED16825C, 0x8ACF1C2B, 0xA779B492,
+ 0xF307F2F0, 0x4E69E2A1, 0x65DAF4CD, 0x0605BED5, 0xD134621F, 0xC4A6FE8A,
+ 0x342E539D, 0xA2F355A0, 0x058AE132, 0xA4F6EB75, 0x0B83EC39, 0x4060EFAA,
+ 0x5E719F06, 0xBD6E1051, 0x3E218AF9, 0x96DD063D, 0xDD3E05AE, 0x4DE6BD46,
+ 0x91548DB5, 0x71C45D05, 0x0406D46F, 0x605015FF, 0x1998FB24, 0xD6BDE997,
+ 0x894043CC, 0x67D99E77, 0xB0E842BD, 0x07898B88, 0xE7195B38, 0x79C8EEDB,
+ 0xA17C0A47, 0x7C420FE9, 0xF8841EC9, 0x00000000, 0x09808683, 0x322BED48,
+ 0x1E1170AC, 0x6C5A724E, 0xFD0EFFFB, 0x0F853856, 0x3DAED51E, 0x362D3927,
+ 0x0A0FD964, 0x685CA621, 0x9B5B54D1, 0x24362E3A, 0x0C0A67B1, 0x9357E70F,
+ 0xB4EE96D2, 0x1B9B919E, 0x80C0C54F, 0x61DC20A2, 0x5A774B69, 0x1C121A16,
+ 0xE293BA0A, 0xC0A02AE5, 0x3C22E043, 0x121B171D, 0x0E090D0B, 0xF28BC7AD,
+ 0x2DB6A8B9, 0x141EA9C8, 0x57F11985, 0xAF75074C, 0xEE99DDBB, 0xA37F60FD,
+ 0xF701269F, 0x5C72F5BC, 0x44663BC5, 0x5BFB7E34, 0x8B432976, 0xCB23C6DC,
+ 0xB6EDFC68, 0xB8E4F163, 0xD731DCCA, 0x42638510, 0x13972240, 0x84C61120,
+ 0x854A247D, 0xD2BB3DF8, 0xAEF93211, 0xC729A16D, 0x1D9E2F4B, 0xDCB230F3,
+ 0x0D8652EC, 0x77C1E3D0, 0x2BB3166C, 0xA970B999, 0x119448FA, 0x47E96422,
+ 0xA8FC8CC4, 0xA0F03F1A, 0x567D2CD8, 0x223390EF, 0x87494EC7, 0xD938D1C1,
+ 0x8CCAA2FE, 0x98D40B36, 0xA6F581CF, 0xA57ADE28, 0xDAB78E26, 0x3FADBFA4,
+ 0x2C3A9DE4, 0x5078920D, 0x6A5FCC9B, 0x547E4662, 0xF68D13C2, 0x90D8B8E8,
+ 0x2E39F75E, 0x82C3AFF5, 0x9F5D80BE, 0x69D0937C, 0x6FD52DA9, 0xCF2512B3,
+ 0xC8AC993B, 0x10187DA7, 0xE89C636E, 0xDB3BBB7B, 0xCD267809, 0x6E5918F4,
+ 0xEC9AB701, 0x834F9AA8, 0xE6956E65, 0xAAFFE67E, 0x21BCCF08, 0xEF15E8E6,
+ 0xBAE79BD9, 0x4A6F36CE, 0xEA9F09D4, 0x29B07CD6, 0x31A4B2AF, 0x2A3F2331,
+ 0xC6A59430, 0x35A266C0, 0x744EBC37, 0xFC82CAA6, 0xE090D0B0, 0x33A7D815,
+ 0xF104984A, 0x41ECDAF7, 0x7FCD500E, 0x1791F62F, 0x764DD68D, 0x43EFB04D,
+ 0xCCAA4D54, 0xE49604DF, 0x9ED1B5E3, 0x4C6A881B, 0xC12C1FB8, 0x4665517F,
+ 0x9D5EEA04, 0x018C355D, 0xFA877473, 0xFB0B412E, 0xB3671D5A, 0x92DBD252,
+ 0xE9105633, 0x6DD64713, 0x9AD7618C, 0x37A10C7A, 0x59F8148E, 0xEB133C89,
+ 0xCEA927EE, 0xB761C935, 0xE11CE5ED, 0x7A47B13C, 0x9CD2DF59, 0x55F2733F,
+ 0x1814CE79, 0x73C737BF, 0x53F7CDEA, 0x5FFDAA5B, 0xDF3D6F14, 0x7844DB86,
+ 0xCAAFF381, 0xB968C43E, 0x3824342C, 0xC2A3405F, 0x161DC372, 0xBCE2250C,
+ 0x283C498B, 0xFF0D9541, 0x39A80171, 0x080CB3DE, 0xD8B4E49C, 0x6456C190,
+ 0x7BCB8461, 0xD532B670, 0x486C5C74, 0xD0B85742
+};
+
+static unsigned
+mul2(unsigned x)
+{
+ x <<= 1;
+ return x ^ ((unsigned)(-(int)(x >> 8)) & 0x11B);
+}
+
+static unsigned
+mul9(unsigned x)
+{
+ return x ^ mul2(mul2(mul2(x)));
+}
+
+static unsigned
+mulb(unsigned x)
+{
+ unsigned x2;
+
+ x2 = mul2(x);
+ return x ^ x2 ^ mul2(mul2(x2));
+}
+
+static unsigned
+muld(unsigned x)
+{
+ unsigned x4;
+
+ x4 = mul2(mul2(x));
+ return x ^ x4 ^ mul2(x4);
+}
+
+static unsigned
+mule(unsigned x)
+{
+ unsigned x2, x4;
+
+ x2 = mul2(x);
+ x4 = mul2(x2);
+ return x2 ^ x4 ^ mul2(x4);
+}
+
+/* see inner.h */
+unsigned
+br_aes_big_keysched_inv(uint32_t *skey, const void *key, size_t key_len)
+{
+ unsigned num_rounds;
+ int i, m;
+
+ /*
+ * Sub-keys for decryption are distinct from encryption sub-keys
+ * in that InvMixColumns() is already applied for the inner
+ * rounds.
+ */
+ num_rounds = br_aes_keysched(skey, key, key_len);
+ m = (int)(num_rounds << 2);
+ for (i = 4; i < m; i ++) {
+ uint32_t p;
+ unsigned p0, p1, p2, p3;
+ uint32_t q0, q1, q2, q3;
+
+ p = skey[i];
+ p0 = p >> 24;
+ p1 = (p >> 16) & 0xFF;
+ p2 = (p >> 8) & 0xFF;
+ p3 = p & 0xFF;
+ q0 = mule(p0) ^ mulb(p1) ^ muld(p2) ^ mul9(p3);
+ q1 = mul9(p0) ^ mule(p1) ^ mulb(p2) ^ muld(p3);
+ q2 = muld(p0) ^ mul9(p1) ^ mule(p2) ^ mulb(p3);
+ q3 = mulb(p0) ^ muld(p1) ^ mul9(p2) ^ mule(p3);
+ skey[i] = (q0 << 24) | (q1 << 16) | (q2 << 8) | q3;
+ }
+ return num_rounds;
+}
+
+static inline uint32_t
+rotr(uint32_t x, int n)
+{
+ return (x << (32 - n)) | (x >> n);
+}
+
+#define iSboxExt0(x) (iSsm0[x])
+#define iSboxExt1(x) (rotr(iSsm0[x], 8))
+#define iSboxExt2(x) (rotr(iSsm0[x], 16))
+#define iSboxExt3(x) (rotr(iSsm0[x], 24))
+
+/* see bearssl.h */
+void
+br_aes_big_decrypt(unsigned num_rounds, const uint32_t *skey, void *data)
+{
+ unsigned char *buf;
+ uint32_t s0, s1, s2, s3;
+ uint32_t t0, t1, t2, t3;
+ unsigned u;
+
+ buf = data;
+ s0 = br_dec32be(buf);
+ s1 = br_dec32be(buf + 4);
+ s2 = br_dec32be(buf + 8);
+ s3 = br_dec32be(buf + 12);
+ s0 ^= skey[(num_rounds << 2) + 0];
+ s1 ^= skey[(num_rounds << 2) + 1];
+ s2 ^= skey[(num_rounds << 2) + 2];
+ s3 ^= skey[(num_rounds << 2) + 3];
+ for (u = num_rounds - 1; u > 0; u --) {
+ uint32_t v0 = iSboxExt0(s0 >> 24)
+ ^ iSboxExt1((s3 >> 16) & 0xFF)
+ ^ iSboxExt2((s2 >> 8) & 0xFF)
+ ^ iSboxExt3(s1 & 0xFF);
+ uint32_t v1 = iSboxExt0(s1 >> 24)
+ ^ iSboxExt1((s0 >> 16) & 0xFF)
+ ^ iSboxExt2((s3 >> 8) & 0xFF)
+ ^ iSboxExt3(s2 & 0xFF);
+ uint32_t v2 = iSboxExt0(s2 >> 24)
+ ^ iSboxExt1((s1 >> 16) & 0xFF)
+ ^ iSboxExt2((s0 >> 8) & 0xFF)
+ ^ iSboxExt3(s3 & 0xFF);
+ uint32_t v3 = iSboxExt0(s3 >> 24)
+ ^ iSboxExt1((s2 >> 16) & 0xFF)
+ ^ iSboxExt2((s1 >> 8) & 0xFF)
+ ^ iSboxExt3(s0 & 0xFF);
+ s0 = v0;
+ s1 = v1;
+ s2 = v2;
+ s3 = v3;
+ s0 ^= skey[u << 2];
+ s1 ^= skey[(u << 2) + 1];
+ s2 ^= skey[(u << 2) + 2];
+ s3 ^= skey[(u << 2) + 3];
+ }
+ t0 = ((uint32_t)iS[s0 >> 24] << 24)
+ | ((uint32_t)iS[(s3 >> 16) & 0xFF] << 16)
+ | ((uint32_t)iS[(s2 >> 8) & 0xFF] << 8)
+ | (uint32_t)iS[s1 & 0xFF];
+ t1 = ((uint32_t)iS[s1 >> 24] << 24)
+ | ((uint32_t)iS[(s0 >> 16) & 0xFF] << 16)
+ | ((uint32_t)iS[(s3 >> 8) & 0xFF] << 8)
+ | (uint32_t)iS[s2 & 0xFF];
+ t2 = ((uint32_t)iS[s2 >> 24] << 24)
+ | ((uint32_t)iS[(s1 >> 16) & 0xFF] << 16)
+ | ((uint32_t)iS[(s0 >> 8) & 0xFF] << 8)
+ | (uint32_t)iS[s3 & 0xFF];
+ t3 = ((uint32_t)iS[s3 >> 24] << 24)
+ | ((uint32_t)iS[(s2 >> 16) & 0xFF] << 16)
+ | ((uint32_t)iS[(s1 >> 8) & 0xFF] << 8)
+ | (uint32_t)iS[s0 & 0xFF];
+ s0 = t0 ^ skey[0];
+ s1 = t1 ^ skey[1];
+ s2 = t2 ^ skey[2];
+ s3 = t3 ^ skey[3];
+ br_enc32be(buf, s0);
+ br_enc32be(buf + 4, s1);
+ br_enc32be(buf + 8, s2);
+ br_enc32be(buf + 12, s3);
+}
--- /dev/null
+/*
+ * 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"
+
+#define S br_aes_S
+
+static const uint32_t Ssm0[] = {
+ 0xC66363A5, 0xF87C7C84, 0xEE777799, 0xF67B7B8D, 0xFFF2F20D, 0xD66B6BBD,
+ 0xDE6F6FB1, 0x91C5C554, 0x60303050, 0x02010103, 0xCE6767A9, 0x562B2B7D,
+ 0xE7FEFE19, 0xB5D7D762, 0x4DABABE6, 0xEC76769A, 0x8FCACA45, 0x1F82829D,
+ 0x89C9C940, 0xFA7D7D87, 0xEFFAFA15, 0xB25959EB, 0x8E4747C9, 0xFBF0F00B,
+ 0x41ADADEC, 0xB3D4D467, 0x5FA2A2FD, 0x45AFAFEA, 0x239C9CBF, 0x53A4A4F7,
+ 0xE4727296, 0x9BC0C05B, 0x75B7B7C2, 0xE1FDFD1C, 0x3D9393AE, 0x4C26266A,
+ 0x6C36365A, 0x7E3F3F41, 0xF5F7F702, 0x83CCCC4F, 0x6834345C, 0x51A5A5F4,
+ 0xD1E5E534, 0xF9F1F108, 0xE2717193, 0xABD8D873, 0x62313153, 0x2A15153F,
+ 0x0804040C, 0x95C7C752, 0x46232365, 0x9DC3C35E, 0x30181828, 0x379696A1,
+ 0x0A05050F, 0x2F9A9AB5, 0x0E070709, 0x24121236, 0x1B80809B, 0xDFE2E23D,
+ 0xCDEBEB26, 0x4E272769, 0x7FB2B2CD, 0xEA75759F, 0x1209091B, 0x1D83839E,
+ 0x582C2C74, 0x341A1A2E, 0x361B1B2D, 0xDC6E6EB2, 0xB45A5AEE, 0x5BA0A0FB,
+ 0xA45252F6, 0x763B3B4D, 0xB7D6D661, 0x7DB3B3CE, 0x5229297B, 0xDDE3E33E,
+ 0x5E2F2F71, 0x13848497, 0xA65353F5, 0xB9D1D168, 0x00000000, 0xC1EDED2C,
+ 0x40202060, 0xE3FCFC1F, 0x79B1B1C8, 0xB65B5BED, 0xD46A6ABE, 0x8DCBCB46,
+ 0x67BEBED9, 0x7239394B, 0x944A4ADE, 0x984C4CD4, 0xB05858E8, 0x85CFCF4A,
+ 0xBBD0D06B, 0xC5EFEF2A, 0x4FAAAAE5, 0xEDFBFB16, 0x864343C5, 0x9A4D4DD7,
+ 0x66333355, 0x11858594, 0x8A4545CF, 0xE9F9F910, 0x04020206, 0xFE7F7F81,
+ 0xA05050F0, 0x783C3C44, 0x259F9FBA, 0x4BA8A8E3, 0xA25151F3, 0x5DA3A3FE,
+ 0x804040C0, 0x058F8F8A, 0x3F9292AD, 0x219D9DBC, 0x70383848, 0xF1F5F504,
+ 0x63BCBCDF, 0x77B6B6C1, 0xAFDADA75, 0x42212163, 0x20101030, 0xE5FFFF1A,
+ 0xFDF3F30E, 0xBFD2D26D, 0x81CDCD4C, 0x180C0C14, 0x26131335, 0xC3ECEC2F,
+ 0xBE5F5FE1, 0x359797A2, 0x884444CC, 0x2E171739, 0x93C4C457, 0x55A7A7F2,
+ 0xFC7E7E82, 0x7A3D3D47, 0xC86464AC, 0xBA5D5DE7, 0x3219192B, 0xE6737395,
+ 0xC06060A0, 0x19818198, 0x9E4F4FD1, 0xA3DCDC7F, 0x44222266, 0x542A2A7E,
+ 0x3B9090AB, 0x0B888883, 0x8C4646CA, 0xC7EEEE29, 0x6BB8B8D3, 0x2814143C,
+ 0xA7DEDE79, 0xBC5E5EE2, 0x160B0B1D, 0xADDBDB76, 0xDBE0E03B, 0x64323256,
+ 0x743A3A4E, 0x140A0A1E, 0x924949DB, 0x0C06060A, 0x4824246C, 0xB85C5CE4,
+ 0x9FC2C25D, 0xBDD3D36E, 0x43ACACEF, 0xC46262A6, 0x399191A8, 0x319595A4,
+ 0xD3E4E437, 0xF279798B, 0xD5E7E732, 0x8BC8C843, 0x6E373759, 0xDA6D6DB7,
+ 0x018D8D8C, 0xB1D5D564, 0x9C4E4ED2, 0x49A9A9E0, 0xD86C6CB4, 0xAC5656FA,
+ 0xF3F4F407, 0xCFEAEA25, 0xCA6565AF, 0xF47A7A8E, 0x47AEAEE9, 0x10080818,
+ 0x6FBABAD5, 0xF0787888, 0x4A25256F, 0x5C2E2E72, 0x381C1C24, 0x57A6A6F1,
+ 0x73B4B4C7, 0x97C6C651, 0xCBE8E823, 0xA1DDDD7C, 0xE874749C, 0x3E1F1F21,
+ 0x964B4BDD, 0x61BDBDDC, 0x0D8B8B86, 0x0F8A8A85, 0xE0707090, 0x7C3E3E42,
+ 0x71B5B5C4, 0xCC6666AA, 0x904848D8, 0x06030305, 0xF7F6F601, 0x1C0E0E12,
+ 0xC26161A3, 0x6A35355F, 0xAE5757F9, 0x69B9B9D0, 0x17868691, 0x99C1C158,
+ 0x3A1D1D27, 0x279E9EB9, 0xD9E1E138, 0xEBF8F813, 0x2B9898B3, 0x22111133,
+ 0xD26969BB, 0xA9D9D970, 0x078E8E89, 0x339494A7, 0x2D9B9BB6, 0x3C1E1E22,
+ 0x15878792, 0xC9E9E920, 0x87CECE49, 0xAA5555FF, 0x50282878, 0xA5DFDF7A,
+ 0x038C8C8F, 0x59A1A1F8, 0x09898980, 0x1A0D0D17, 0x65BFBFDA, 0xD7E6E631,
+ 0x844242C6, 0xD06868B8, 0x824141C3, 0x299999B0, 0x5A2D2D77, 0x1E0F0F11,
+ 0x7BB0B0CB, 0xA85454FC, 0x6DBBBBD6, 0x2C16163A
+};
+
+static inline uint32_t
+rotr(uint32_t x, int n)
+{
+ return (x << (32 - n)) | (x >> n);
+}
+
+#define SboxExt0(x) (Ssm0[x])
+#define SboxExt1(x) (rotr(Ssm0[x], 8))
+#define SboxExt2(x) (rotr(Ssm0[x], 16))
+#define SboxExt3(x) (rotr(Ssm0[x], 24))
+
+
+/* see bearssl.h */
+void
+br_aes_big_encrypt(unsigned num_rounds, const uint32_t *skey, void *data)
+{
+ unsigned char *buf;
+ uint32_t s0, s1, s2, s3;
+ uint32_t t0, t1, t2, t3;
+ unsigned u;
+
+ buf = data;
+ s0 = br_dec32be(buf);
+ s1 = br_dec32be(buf + 4);
+ s2 = br_dec32be(buf + 8);
+ s3 = br_dec32be(buf + 12);
+ s0 ^= skey[0];
+ s1 ^= skey[1];
+ s2 ^= skey[2];
+ s3 ^= skey[3];
+ for (u = 1; u < num_rounds; u ++) {
+ uint32_t v0, v1, v2, v3;
+
+ v0 = SboxExt0(s0 >> 24)
+ ^ SboxExt1((s1 >> 16) & 0xFF)
+ ^ SboxExt2((s2 >> 8) & 0xFF)
+ ^ SboxExt3(s3 & 0xFF);
+ v1 = SboxExt0(s1 >> 24)
+ ^ SboxExt1((s2 >> 16) & 0xFF)
+ ^ SboxExt2((s3 >> 8) & 0xFF)
+ ^ SboxExt3(s0 & 0xFF);
+ v2 = SboxExt0(s2 >> 24)
+ ^ SboxExt1((s3 >> 16) & 0xFF)
+ ^ SboxExt2((s0 >> 8) & 0xFF)
+ ^ SboxExt3(s1 & 0xFF);
+ v3 = SboxExt0(s3 >> 24)
+ ^ SboxExt1((s0 >> 16) & 0xFF)
+ ^ SboxExt2((s1 >> 8) & 0xFF)
+ ^ SboxExt3(s2 & 0xFF);
+ s0 = v0;
+ s1 = v1;
+ s2 = v2;
+ s3 = v3;
+ s0 ^= skey[u << 2];
+ s1 ^= skey[(u << 2) + 1];
+ s2 ^= skey[(u << 2) + 2];
+ s3 ^= skey[(u << 2) + 3];
+ }
+ t0 = ((uint32_t)S[s0 >> 24] << 24)
+ | ((uint32_t)S[(s1 >> 16) & 0xFF] << 16)
+ | ((uint32_t)S[(s2 >> 8) & 0xFF] << 8)
+ | (uint32_t)S[s3 & 0xFF];
+ t1 = ((uint32_t)S[s1 >> 24] << 24)
+ | ((uint32_t)S[(s2 >> 16) & 0xFF] << 16)
+ | ((uint32_t)S[(s3 >> 8) & 0xFF] << 8)
+ | (uint32_t)S[s0 & 0xFF];
+ t2 = ((uint32_t)S[s2 >> 24] << 24)
+ | ((uint32_t)S[(s3 >> 16) & 0xFF] << 16)
+ | ((uint32_t)S[(s0 >> 8) & 0xFF] << 8)
+ | (uint32_t)S[s1 & 0xFF];
+ t3 = ((uint32_t)S[s3 >> 24] << 24)
+ | ((uint32_t)S[(s0 >> 16) & 0xFF] << 16)
+ | ((uint32_t)S[(s1 >> 8) & 0xFF] << 8)
+ | (uint32_t)S[s2 & 0xFF];
+ s0 = t0 ^ skey[num_rounds << 2];
+ s1 = t1 ^ skey[(num_rounds << 2) + 1];
+ s2 = t2 ^ skey[(num_rounds << 2) + 2];
+ s3 = t3 ^ skey[(num_rounds << 2) + 3];
+ br_enc32be(buf, s0);
+ br_enc32be(buf + 4, s1);
+ br_enc32be(buf + 8, s2);
+ br_enc32be(buf + 12, s3);
+}
--- /dev/null
+/*
+ * 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"
+
+static const uint32_t Rcon[] = {
+ 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000,
+ 0x40000000, 0x80000000, 0x1B000000, 0x36000000
+};
+
+#define S br_aes_S
+
+/* see inner.h */
+const unsigned char br_aes_S[] = {
+ 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B,
+ 0xFE, 0xD7, 0xAB, 0x76, 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0,
+ 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 0xB7, 0xFD, 0x93, 0x26,
+ 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
+ 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2,
+ 0xEB, 0x27, 0xB2, 0x75, 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0,
+ 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 0x53, 0xD1, 0x00, 0xED,
+ 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
+ 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F,
+ 0x50, 0x3C, 0x9F, 0xA8, 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5,
+ 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 0xCD, 0x0C, 0x13, 0xEC,
+ 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
+ 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14,
+ 0xDE, 0x5E, 0x0B, 0xDB, 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C,
+ 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 0xE7, 0xC8, 0x37, 0x6D,
+ 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
+ 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F,
+ 0x4B, 0xBD, 0x8B, 0x8A, 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E,
+ 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 0xE1, 0xF8, 0x98, 0x11,
+ 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
+ 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F,
+ 0xB0, 0x54, 0xBB, 0x16
+};
+
+static uint32_t
+SubWord(uint32_t x)
+{
+ return ((uint32_t)S[x >> 24] << 24)
+ | ((uint32_t)S[(x >> 16) & 0xFF] << 16)
+ | ((uint32_t)S[(x >> 8) & 0xFF] << 8)
+ | (uint32_t)S[x & 0xFF];
+}
+
+/* see inner.h */
+unsigned
+br_aes_keysched(uint32_t *skey, const void *key, size_t key_len)
+{
+ unsigned num_rounds;
+ int i, j, k, nk, nkf;
+
+ switch (key_len) {
+ case 16:
+ num_rounds = 10;
+ break;
+ case 24:
+ num_rounds = 12;
+ break;
+ case 32:
+ num_rounds = 14;
+ break;
+ default:
+ /* abort(); */
+ return 0;
+ }
+ nk = (int)(key_len >> 2);
+ nkf = (int)((num_rounds + 1) << 2);
+ for (i = 0; i < nk; i ++) {
+ skey[i] = br_dec32be((const unsigned char *)key + (i << 2));
+ }
+ for (i = nk, j = 0, k = 0; i < nkf; i ++) {
+ uint32_t tmp;
+
+ tmp = skey[i - 1];
+ if (j == 0) {
+ tmp = (tmp << 8) | (tmp >> 24);
+ tmp = SubWord(tmp) ^ Rcon[k];
+ } else if (nk > 6 && j == 4) {
+ tmp = SubWord(tmp);
+ }
+ skey[i] = skey[i - nk] ^ tmp;
+ if (++ j == nk) {
+ j = 0;
+ k ++;
+ }
+ }
+ return num_rounds;
+}
--- /dev/null
+/*
+ * 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 inner.h */
+void
+br_aes_ct_bitslice_Sbox(uint32_t *q)
+{
+ /*
+ * This S-box implementation is a straightforward translation of
+ * the circuit described by Boyar and Peralta in "A new
+ * combinational logic minimization technique with applications
+ * to cryptology" (https://eprint.iacr.org/2009/191.pdf).
+ *
+ * Note that variables x* (input) and s* (output) are numbered
+ * in "reverse" order (x0 is the high bit, x7 is the low bit).
+ */
+
+ uint32_t x0, x1, x2, x3, x4, x5, x6, x7;
+ uint32_t y1, y2, y3, y4, y5, y6, y7, y8, y9;
+ uint32_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19;
+ uint32_t y20, y21;
+ uint32_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9;
+ uint32_t z10, z11, z12, z13, z14, z15, z16, z17;
+ uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9;
+ uint32_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19;
+ uint32_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29;
+ uint32_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39;
+ uint32_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49;
+ uint32_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59;
+ uint32_t t60, t61, t62, t63, t64, t65, t66, t67;
+ uint32_t s0, s1, s2, s3, s4, s5, s6, s7;
+
+ x0 = q[7];
+ x1 = q[6];
+ x2 = q[5];
+ x3 = q[4];
+ x4 = q[3];
+ x5 = q[2];
+ x6 = q[1];
+ x7 = q[0];
+
+ /*
+ * Top linear transformation.
+ */
+ y14 = x3 ^ x5;
+ y13 = x0 ^ x6;
+ y9 = x0 ^ x3;
+ y8 = x0 ^ x5;
+ t0 = x1 ^ x2;
+ y1 = t0 ^ x7;
+ y4 = y1 ^ x3;
+ y12 = y13 ^ y14;
+ y2 = y1 ^ x0;
+ y5 = y1 ^ x6;
+ y3 = y5 ^ y8;
+ t1 = x4 ^ y12;
+ y15 = t1 ^ x5;
+ y20 = t1 ^ x1;
+ y6 = y15 ^ x7;
+ y10 = y15 ^ t0;
+ y11 = y20 ^ y9;
+ y7 = x7 ^ y11;
+ y17 = y10 ^ y11;
+ y19 = y10 ^ y8;
+ y16 = t0 ^ y11;
+ y21 = y13 ^ y16;
+ y18 = x0 ^ y16;
+
+ /*
+ * Non-linear section.
+ */
+ t2 = y12 & y15;
+ t3 = y3 & y6;
+ t4 = t3 ^ t2;
+ t5 = y4 & x7;
+ t6 = t5 ^ t2;
+ t7 = y13 & y16;
+ t8 = y5 & y1;
+ t9 = t8 ^ t7;
+ t10 = y2 & y7;
+ t11 = t10 ^ t7;
+ t12 = y9 & y11;
+ t13 = y14 & y17;
+ t14 = t13 ^ t12;
+ t15 = y8 & y10;
+ t16 = t15 ^ t12;
+ t17 = t4 ^ t14;
+ t18 = t6 ^ t16;
+ t19 = t9 ^ t14;
+ t20 = t11 ^ t16;
+ t21 = t17 ^ y20;
+ t22 = t18 ^ y19;
+ t23 = t19 ^ y21;
+ t24 = t20 ^ y18;
+
+ t25 = t21 ^ t22;
+ t26 = t21 & t23;
+ t27 = t24 ^ t26;
+ t28 = t25 & t27;
+ t29 = t28 ^ t22;
+ t30 = t23 ^ t24;
+ t31 = t22 ^ t26;
+ t32 = t31 & t30;
+ t33 = t32 ^ t24;
+ t34 = t23 ^ t33;
+ t35 = t27 ^ t33;
+ t36 = t24 & t35;
+ t37 = t36 ^ t34;
+ t38 = t27 ^ t36;
+ t39 = t29 & t38;
+ t40 = t25 ^ t39;
+
+ t41 = t40 ^ t37;
+ t42 = t29 ^ t33;
+ t43 = t29 ^ t40;
+ t44 = t33 ^ t37;
+ t45 = t42 ^ t41;
+ z0 = t44 & y15;
+ z1 = t37 & y6;
+ z2 = t33 & x7;
+ z3 = t43 & y16;
+ z4 = t40 & y1;
+ z5 = t29 & y7;
+ z6 = t42 & y11;
+ z7 = t45 & y17;
+ z8 = t41 & y10;
+ z9 = t44 & y12;
+ z10 = t37 & y3;
+ z11 = t33 & y4;
+ z12 = t43 & y13;
+ z13 = t40 & y5;
+ z14 = t29 & y2;
+ z15 = t42 & y9;
+ z16 = t45 & y14;
+ z17 = t41 & y8;
+
+ /*
+ * Bottom linear transformation.
+ */
+ t46 = z15 ^ z16;
+ t47 = z10 ^ z11;
+ t48 = z5 ^ z13;
+ t49 = z9 ^ z10;
+ t50 = z2 ^ z12;
+ t51 = z2 ^ z5;
+ t52 = z7 ^ z8;
+ t53 = z0 ^ z3;
+ t54 = z6 ^ z7;
+ t55 = z16 ^ z17;
+ t56 = z12 ^ t48;
+ t57 = t50 ^ t53;
+ t58 = z4 ^ t46;
+ t59 = z3 ^ t54;
+ t60 = t46 ^ t57;
+ t61 = z14 ^ t57;
+ t62 = t52 ^ t58;
+ t63 = t49 ^ t58;
+ t64 = z4 ^ t59;
+ t65 = t61 ^ t62;
+ t66 = z1 ^ t63;
+ s0 = t59 ^ t63;
+ s6 = t56 ^ ~t62;
+ s7 = t48 ^ ~t60;
+ t67 = t64 ^ t65;
+ s3 = t53 ^ t66;
+ s4 = t51 ^ t66;
+ s5 = t47 ^ t65;
+ s1 = t64 ^ ~s3;
+ s2 = t55 ^ ~t67;
+
+ q[7] = s0;
+ q[6] = s1;
+ q[5] = s2;
+ q[4] = s3;
+ q[3] = s4;
+ q[2] = s5;
+ q[1] = s6;
+ q[0] = s7;
+}
+
+/* see inner.h */
+void
+br_aes_ct_ortho(uint32_t *q)
+{
+#define SWAPN(cl, ch, s, x, y) do { \
+ uint32_t a, b; \
+ a = (x); \
+ b = (y); \
+ (x) = (a & (uint32_t)cl) | ((b & (uint32_t)cl) << (s)); \
+ (y) = ((a & (uint32_t)ch) >> (s)) | (b & (uint32_t)ch); \
+ } while (0)
+
+#define SWAP2(x, y) SWAPN(0x55555555, 0xAAAAAAAA, 1, x, y)
+#define SWAP4(x, y) SWAPN(0x33333333, 0xCCCCCCCC, 2, x, y)
+#define SWAP8(x, y) SWAPN(0x0F0F0F0F, 0xF0F0F0F0, 4, x, y)
+
+ SWAP2(q[0], q[1]);
+ SWAP2(q[2], q[3]);
+ SWAP2(q[4], q[5]);
+ SWAP2(q[6], q[7]);
+
+ SWAP4(q[0], q[2]);
+ SWAP4(q[1], q[3]);
+ SWAP4(q[4], q[6]);
+ SWAP4(q[5], q[7]);
+
+ SWAP8(q[0], q[4]);
+ SWAP8(q[1], q[5]);
+ SWAP8(q[2], q[6]);
+ SWAP8(q[3], q[7]);
+}
+
+static const unsigned char Rcon[] = {
+ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36
+};
+
+static uint32_t
+sub_word(uint32_t x)
+{
+ uint32_t q[8];
+ int i;
+
+ for (i = 0; i < 8; i ++) {
+ q[i] = x;
+ }
+ br_aes_ct_ortho(q);
+ br_aes_ct_bitslice_Sbox(q);
+ br_aes_ct_ortho(q);
+ return q[0];
+}
+
+/* see inner.h */
+unsigned
+br_aes_ct_keysched(uint32_t *comp_skey, const void *key, size_t key_len)
+{
+ unsigned num_rounds;
+ int i, j, k, nk, nkf;
+ uint32_t tmp;
+ uint32_t skey[120];
+
+ switch (key_len) {
+ case 16:
+ num_rounds = 10;
+ break;
+ case 24:
+ num_rounds = 12;
+ break;
+ case 32:
+ num_rounds = 14;
+ break;
+ default:
+ /* abort(); */
+ return 0;
+ }
+ nk = (int)(key_len >> 2);
+ nkf = (int)((num_rounds + 1) << 2);
+ tmp = 0;
+ for (i = 0; i < nk; i ++) {
+ tmp = br_dec32le((const unsigned char *)key + (i << 2));
+ skey[(i << 1) + 0] = tmp;
+ skey[(i << 1) + 1] = tmp;
+ }
+ for (i = nk, j = 0, k = 0; i < nkf; i ++) {
+ if (j == 0) {
+ tmp = (tmp << 24) | (tmp >> 8);
+ tmp = sub_word(tmp) ^ Rcon[k];
+ } else if (nk > 6 && j == 4) {
+ tmp = sub_word(tmp);
+ }
+ tmp ^= skey[(i - nk) << 1];
+ skey[(i << 1) + 0] = tmp;
+ skey[(i << 1) + 1] = tmp;
+ if (++ j == nk) {
+ j = 0;
+ k ++;
+ }
+ }
+ for (i = 0; i < nkf; i += 4) {
+ br_aes_ct_ortho(skey + (i << 1));
+ }
+ for (i = 0, j = 0; i < nkf; i ++, j += 2) {
+ comp_skey[i] = (skey[j + 0] & 0x55555555)
+ | (skey[j + 1] & 0xAAAAAAAA);
+ }
+ return num_rounds;
+}
+
+/* see inner.h */
+void
+br_aes_ct_skey_expand(uint32_t *skey,
+ unsigned num_rounds, const uint32_t *comp_skey)
+{
+ unsigned u, v, n;
+
+ n = (num_rounds + 1) << 2;
+ for (u = 0, v = 0; u < n; u ++, v += 2) {
+ uint32_t x, y;
+
+ x = y = comp_skey[u];
+ x &= 0x55555555;
+ skey[v + 0] = x | (x << 1);
+ y &= 0xAAAAAAAA;
+ skey[v + 1] = y | (y >> 1);
+ }
+}
--- /dev/null
+/*
+ * 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 inner.h */
+void
+br_aes_ct64_bitslice_Sbox(uint64_t *q)
+{
+ /*
+ * This S-box implementation is a straightforward translation of
+ * the circuit described by Boyar and Peralta in "A new
+ * combinational logic minimization technique with applications
+ * to cryptology" (https://eprint.iacr.org/2009/191.pdf).
+ *
+ * Note that variables x* (input) and s* (output) are numbered
+ * in "reverse" order (x0 is the high bit, x7 is the low bit).
+ */
+
+ uint64_t x0, x1, x2, x3, x4, x5, x6, x7;
+ uint64_t y1, y2, y3, y4, y5, y6, y7, y8, y9;
+ uint64_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19;
+ uint64_t y20, y21;
+ uint64_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9;
+ uint64_t z10, z11, z12, z13, z14, z15, z16, z17;
+ uint64_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9;
+ uint64_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19;
+ uint64_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29;
+ uint64_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39;
+ uint64_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49;
+ uint64_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59;
+ uint64_t t60, t61, t62, t63, t64, t65, t66, t67;
+ uint64_t s0, s1, s2, s3, s4, s5, s6, s7;
+
+ x0 = q[7];
+ x1 = q[6];
+ x2 = q[5];
+ x3 = q[4];
+ x4 = q[3];
+ x5 = q[2];
+ x6 = q[1];
+ x7 = q[0];
+
+ /*
+ * Top linear transformation.
+ */
+ y14 = x3 ^ x5;
+ y13 = x0 ^ x6;
+ y9 = x0 ^ x3;
+ y8 = x0 ^ x5;
+ t0 = x1 ^ x2;
+ y1 = t0 ^ x7;
+ y4 = y1 ^ x3;
+ y12 = y13 ^ y14;
+ y2 = y1 ^ x0;
+ y5 = y1 ^ x6;
+ y3 = y5 ^ y8;
+ t1 = x4 ^ y12;
+ y15 = t1 ^ x5;
+ y20 = t1 ^ x1;
+ y6 = y15 ^ x7;
+ y10 = y15 ^ t0;
+ y11 = y20 ^ y9;
+ y7 = x7 ^ y11;
+ y17 = y10 ^ y11;
+ y19 = y10 ^ y8;
+ y16 = t0 ^ y11;
+ y21 = y13 ^ y16;
+ y18 = x0 ^ y16;
+
+ /*
+ * Non-linear section.
+ */
+ t2 = y12 & y15;
+ t3 = y3 & y6;
+ t4 = t3 ^ t2;
+ t5 = y4 & x7;
+ t6 = t5 ^ t2;
+ t7 = y13 & y16;
+ t8 = y5 & y1;
+ t9 = t8 ^ t7;
+ t10 = y2 & y7;
+ t11 = t10 ^ t7;
+ t12 = y9 & y11;
+ t13 = y14 & y17;
+ t14 = t13 ^ t12;
+ t15 = y8 & y10;
+ t16 = t15 ^ t12;
+ t17 = t4 ^ t14;
+ t18 = t6 ^ t16;
+ t19 = t9 ^ t14;
+ t20 = t11 ^ t16;
+ t21 = t17 ^ y20;
+ t22 = t18 ^ y19;
+ t23 = t19 ^ y21;
+ t24 = t20 ^ y18;
+
+ t25 = t21 ^ t22;
+ t26 = t21 & t23;
+ t27 = t24 ^ t26;
+ t28 = t25 & t27;
+ t29 = t28 ^ t22;
+ t30 = t23 ^ t24;
+ t31 = t22 ^ t26;
+ t32 = t31 & t30;
+ t33 = t32 ^ t24;
+ t34 = t23 ^ t33;
+ t35 = t27 ^ t33;
+ t36 = t24 & t35;
+ t37 = t36 ^ t34;
+ t38 = t27 ^ t36;
+ t39 = t29 & t38;
+ t40 = t25 ^ t39;
+
+ t41 = t40 ^ t37;
+ t42 = t29 ^ t33;
+ t43 = t29 ^ t40;
+ t44 = t33 ^ t37;
+ t45 = t42 ^ t41;
+ z0 = t44 & y15;
+ z1 = t37 & y6;
+ z2 = t33 & x7;
+ z3 = t43 & y16;
+ z4 = t40 & y1;
+ z5 = t29 & y7;
+ z6 = t42 & y11;
+ z7 = t45 & y17;
+ z8 = t41 & y10;
+ z9 = t44 & y12;
+ z10 = t37 & y3;
+ z11 = t33 & y4;
+ z12 = t43 & y13;
+ z13 = t40 & y5;
+ z14 = t29 & y2;
+ z15 = t42 & y9;
+ z16 = t45 & y14;
+ z17 = t41 & y8;
+
+ /*
+ * Bottom linear transformation.
+ */
+ t46 = z15 ^ z16;
+ t47 = z10 ^ z11;
+ t48 = z5 ^ z13;
+ t49 = z9 ^ z10;
+ t50 = z2 ^ z12;
+ t51 = z2 ^ z5;
+ t52 = z7 ^ z8;
+ t53 = z0 ^ z3;
+ t54 = z6 ^ z7;
+ t55 = z16 ^ z17;
+ t56 = z12 ^ t48;
+ t57 = t50 ^ t53;
+ t58 = z4 ^ t46;
+ t59 = z3 ^ t54;
+ t60 = t46 ^ t57;
+ t61 = z14 ^ t57;
+ t62 = t52 ^ t58;
+ t63 = t49 ^ t58;
+ t64 = z4 ^ t59;
+ t65 = t61 ^ t62;
+ t66 = z1 ^ t63;
+ s0 = t59 ^ t63;
+ s6 = t56 ^ ~t62;
+ s7 = t48 ^ ~t60;
+ t67 = t64 ^ t65;
+ s3 = t53 ^ t66;
+ s4 = t51 ^ t66;
+ s5 = t47 ^ t65;
+ s1 = t64 ^ ~s3;
+ s2 = t55 ^ ~t67;
+
+ q[7] = s0;
+ q[6] = s1;
+ q[5] = s2;
+ q[4] = s3;
+ q[3] = s4;
+ q[2] = s5;
+ q[1] = s6;
+ q[0] = s7;
+}
+
+/* see inner.h */
+void
+br_aes_ct64_ortho(uint64_t *q)
+{
+#define SWAPN(cl, ch, s, x, y) do { \
+ uint64_t a, b; \
+ a = (x); \
+ b = (y); \
+ (x) = (a & (uint64_t)cl) | ((b & (uint64_t)cl) << (s)); \
+ (y) = ((a & (uint64_t)ch) >> (s)) | (b & (uint64_t)ch); \
+ } while (0)
+
+#define SWAP2(x, y) SWAPN(0x5555555555555555, 0xAAAAAAAAAAAAAAAA, 1, x, y)
+#define SWAP4(x, y) SWAPN(0x3333333333333333, 0xCCCCCCCCCCCCCCCC, 2, x, y)
+#define SWAP8(x, y) SWAPN(0x0F0F0F0F0F0F0F0F, 0xF0F0F0F0F0F0F0F0, 4, x, y)
+
+ SWAP2(q[0], q[1]);
+ SWAP2(q[2], q[3]);
+ SWAP2(q[4], q[5]);
+ SWAP2(q[6], q[7]);
+
+ SWAP4(q[0], q[2]);
+ SWAP4(q[1], q[3]);
+ SWAP4(q[4], q[6]);
+ SWAP4(q[5], q[7]);
+
+ SWAP8(q[0], q[4]);
+ SWAP8(q[1], q[5]);
+ SWAP8(q[2], q[6]);
+ SWAP8(q[3], q[7]);
+}
+
+/* see inner.h */
+void
+br_aes_ct64_interleave_in(uint64_t *q0, uint64_t *q1, const uint32_t *w)
+{
+ uint64_t x0, x1, x2, x3;
+
+ x0 = w[0];
+ x1 = w[1];
+ x2 = w[2];
+ x3 = w[3];
+ x0 |= (x0 << 16);
+ x1 |= (x1 << 16);
+ x2 |= (x2 << 16);
+ x3 |= (x3 << 16);
+ x0 &= (uint64_t)0x0000FFFF0000FFFF;
+ x1 &= (uint64_t)0x0000FFFF0000FFFF;
+ x2 &= (uint64_t)0x0000FFFF0000FFFF;
+ x3 &= (uint64_t)0x0000FFFF0000FFFF;
+ x0 |= (x0 << 8);
+ x1 |= (x1 << 8);
+ x2 |= (x2 << 8);
+ x3 |= (x3 << 8);
+ x0 &= (uint64_t)0x00FF00FF00FF00FF;
+ x1 &= (uint64_t)0x00FF00FF00FF00FF;
+ x2 &= (uint64_t)0x00FF00FF00FF00FF;
+ x3 &= (uint64_t)0x00FF00FF00FF00FF;
+ *q0 = x0 | (x2 << 8);
+ *q1 = x1 | (x3 << 8);
+}
+
+/* see inner.h */
+void
+br_aes_ct64_interleave_out(uint32_t *w, uint64_t q0, uint64_t q1)
+{
+ uint64_t x0, x1, x2, x3;
+
+ x0 = q0 & (uint64_t)0x00FF00FF00FF00FF;
+ x1 = q1 & (uint64_t)0x00FF00FF00FF00FF;
+ x2 = (q0 >> 8) & (uint64_t)0x00FF00FF00FF00FF;
+ x3 = (q1 >> 8) & (uint64_t)0x00FF00FF00FF00FF;
+ x0 |= (x0 >> 8);
+ x1 |= (x1 >> 8);
+ x2 |= (x2 >> 8);
+ x3 |= (x3 >> 8);
+ x0 &= (uint64_t)0x0000FFFF0000FFFF;
+ x1 &= (uint64_t)0x0000FFFF0000FFFF;
+ x2 &= (uint64_t)0x0000FFFF0000FFFF;
+ x3 &= (uint64_t)0x0000FFFF0000FFFF;
+ w[0] = (uint32_t)x0 | (uint32_t)(x0 >> 16);
+ w[1] = (uint32_t)x1 | (uint32_t)(x1 >> 16);
+ w[2] = (uint32_t)x2 | (uint32_t)(x2 >> 16);
+ w[3] = (uint32_t)x3 | (uint32_t)(x3 >> 16);
+}
+
+static const unsigned char Rcon[] = {
+ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36
+};
+
+static uint32_t
+sub_word(uint32_t x)
+{
+ uint64_t q[8];
+
+ memset(q, 0, sizeof q);
+ q[0] = x;
+ br_aes_ct64_ortho(q);
+ br_aes_ct64_bitslice_Sbox(q);
+ br_aes_ct64_ortho(q);
+ return (uint32_t)q[0];
+}
+
+/* see inner.h */
+unsigned
+br_aes_ct64_keysched(uint64_t *comp_skey, const void *key, size_t key_len)
+{
+ unsigned num_rounds;
+ int i, j, k, nk, nkf;
+ uint32_t tmp;
+ uint32_t skey[60];
+
+ switch (key_len) {
+ case 16:
+ num_rounds = 10;
+ break;
+ case 24:
+ num_rounds = 12;
+ break;
+ case 32:
+ num_rounds = 14;
+ break;
+ default:
+ /* abort(); */
+ return 0;
+ }
+ nk = (int)(key_len >> 2);
+ nkf = (int)((num_rounds + 1) << 2);
+ br_range_dec32le(skey, (key_len >> 2), key);
+ tmp = skey[(key_len >> 2) - 1];
+ for (i = nk, j = 0, k = 0; i < nkf; i ++) {
+ if (j == 0) {
+ tmp = (tmp << 24) | (tmp >> 8);
+ tmp = sub_word(tmp) ^ Rcon[k];
+ } else if (nk > 6 && j == 4) {
+ tmp = sub_word(tmp);
+ }
+ tmp ^= skey[i - nk];
+ skey[i] = tmp;
+ if (++ j == nk) {
+ j = 0;
+ k ++;
+ }
+ }
+
+ for (i = 0, j = 0; i < nkf; i += 4, j += 2) {
+ uint64_t q[8];
+
+ br_aes_ct64_interleave_in(&q[0], &q[4], skey + i);
+ q[1] = q[0];
+ q[2] = q[0];
+ q[3] = q[0];
+ q[5] = q[4];
+ q[6] = q[4];
+ q[7] = q[4];
+ br_aes_ct64_ortho(q);
+ comp_skey[j + 0] =
+ (q[0] & (uint64_t)0x1111111111111111)
+ | (q[1] & (uint64_t)0x2222222222222222)
+ | (q[2] & (uint64_t)0x4444444444444444)
+ | (q[3] & (uint64_t)0x8888888888888888);
+ comp_skey[j + 1] =
+ (q[4] & (uint64_t)0x1111111111111111)
+ | (q[5] & (uint64_t)0x2222222222222222)
+ | (q[6] & (uint64_t)0x4444444444444444)
+ | (q[7] & (uint64_t)0x8888888888888888);
+ }
+ return num_rounds;
+}
+
+/* see inner.h */
+void
+br_aes_ct64_skey_expand(uint64_t *skey,
+ unsigned num_rounds, const uint64_t *comp_skey)
+{
+ unsigned u, v, n;
+
+ n = (num_rounds + 1) << 2;
+ for (u = 0, v = 0; u < n; u ++, v += 4) {
+ uint64_t x0, x1, x2, x3;
+
+ x0 = x1 = x2 = x3 = comp_skey[u];
+ x0 &= (uint64_t)0x1111111111111111;
+ x1 &= (uint64_t)0x2222222222222222;
+ x2 &= (uint64_t)0x4444444444444444;
+ x3 &= (uint64_t)0x8888888888888888;
+ x1 >>= 1;
+ x2 >>= 2;
+ x3 >>= 3;
+ skey[v + 0] = (x0 << 4) - x0;
+ skey[v + 1] = (x1 << 4) - x1;
+ skey[v + 2] = (x2 << 4) - x2;
+ skey[v + 3] = (x3 << 4) - x3;
+ }
+}
--- /dev/null
+/*
+ * 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_block.h */
+void
+br_aes_ct64_cbcdec_init(br_aes_ct64_cbcdec_keys *ctx,
+ const void *key, size_t len)
+{
+ ctx->vtable = &br_aes_ct64_cbcdec_vtable;
+ ctx->num_rounds = br_aes_ct64_keysched(ctx->skey, key, len);
+}
+
+/* see bearssl_block.h */
+void
+br_aes_ct64_cbcdec_run(const br_aes_ct64_cbcdec_keys *ctx,
+ void *iv, void *data, size_t len)
+{
+ unsigned char *buf;
+ uint64_t sk_exp[240];
+ uint32_t ivw[4];
+
+ br_aes_ct64_skey_expand(sk_exp, ctx->num_rounds, ctx->skey);
+ br_range_dec32le(ivw, 4, iv);
+ buf = data;
+ while (len > 0) {
+ uint64_t q[8];
+ uint32_t w1[16], w2[16];
+ int i;
+
+ if (len >= 64) {
+ br_range_dec32le(w1, 16, buf);
+ } else {
+ br_range_dec32le(w1, len >> 2, buf);
+ }
+ for (i = 0; i < 4; i ++) {
+ br_aes_ct64_interleave_in(
+ &q[i], &q[i + 4], w1 + (i << 2));
+ }
+ br_aes_ct64_ortho(q);
+ br_aes_ct64_bitslice_decrypt(ctx->num_rounds, sk_exp, q);
+ br_aes_ct64_ortho(q);
+ for (i = 0; i < 4; i ++) {
+ br_aes_ct64_interleave_out(
+ w2 + (i << 2), q[i], q[i + 4]);
+ }
+ for (i = 0; i < 4; i ++) {
+ w2[i] ^= ivw[i];
+ }
+ if (len >= 64) {
+ for (i = 4; i < 16; i ++) {
+ w2[i] ^= w1[i - 4];
+ }
+ memcpy(ivw, w1 + 12, sizeof ivw);
+ br_range_enc32le(buf, w2, 16);
+ } else {
+ int j;
+
+ j = (int)(len >> 2);
+ for (i = 4; i < j; i ++) {
+ w2[i] ^= w1[i - 4];
+ }
+ memcpy(ivw, w1 + j - 4, sizeof ivw);
+ br_range_enc32le(buf, w2, j);
+ break;
+ }
+ buf += 64;
+ len -= 64;
+ }
+ br_range_enc32le(iv, ivw, 4);
+}
+
+/* see bearssl_block.h */
+const br_block_cbcdec_class br_aes_ct64_cbcdec_vtable = {
+ sizeof(br_aes_ct64_cbcdec_keys),
+ 16,
+ 4,
+ (void (*)(const br_block_cbcdec_class **, const void *, size_t))
+ &br_aes_ct64_cbcdec_init,
+ (void (*)(const br_block_cbcdec_class *const *, void *, void *, size_t))
+ &br_aes_ct64_cbcdec_run
+};
--- /dev/null
+/*
+ * 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_block.h */
+void
+br_aes_ct64_cbcenc_init(br_aes_ct64_cbcenc_keys *ctx,
+ const void *key, size_t len)
+{
+ ctx->vtable = &br_aes_ct64_cbcenc_vtable;
+ ctx->num_rounds = br_aes_ct64_keysched(ctx->skey, key, len);
+}
+
+/* see bearssl_block.h */
+void
+br_aes_ct64_cbcenc_run(const br_aes_ct64_cbcenc_keys *ctx,
+ void *iv, void *data, size_t len)
+{
+ unsigned char *buf;
+ uint64_t sk_exp[240];
+ uint32_t ivw[4];
+
+ br_aes_ct64_skey_expand(sk_exp, ctx->num_rounds, ctx->skey);
+ br_range_dec32le(ivw, 4, iv);
+ buf = data;
+ while (len > 0) {
+ uint32_t w[4];
+ uint64_t q[8];
+
+ w[0] = ivw[0] ^ br_dec32le(buf);
+ w[1] = ivw[1] ^ br_dec32le(buf + 4);
+ w[2] = ivw[2] ^ br_dec32le(buf + 8);
+ w[3] = ivw[3] ^ br_dec32le(buf + 12);
+ br_aes_ct64_interleave_in(&q[0], &q[4], w);
+ br_aes_ct64_ortho(q);
+ br_aes_ct64_bitslice_encrypt(ctx->num_rounds, sk_exp, q);
+ br_aes_ct64_ortho(q);
+ br_aes_ct64_interleave_out(w, q[0], q[4]);
+ memcpy(ivw, w, sizeof w);
+ br_enc32le(buf, w[0]);
+ br_enc32le(buf + 4, w[1]);
+ br_enc32le(buf + 8, w[2]);
+ br_enc32le(buf + 12, w[3]);
+ buf += 16;
+ len -= 16;
+ }
+ br_range_enc32le(iv, ivw, 4);
+}
+
+/* see bearssl_block.h */
+const br_block_cbcenc_class br_aes_ct64_cbcenc_vtable = {
+ sizeof(br_aes_ct64_cbcenc_keys),
+ 16,
+ 4,
+ (void (*)(const br_block_cbcenc_class **, const void *, size_t))
+ &br_aes_ct64_cbcenc_init,
+ (void (*)(const br_block_cbcenc_class *const *, void *, void *, size_t))
+ &br_aes_ct64_cbcenc_run
+};
--- /dev/null
+/*
+ * 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_block.h */
+void
+br_aes_ct64_ctr_init(br_aes_ct64_ctr_keys *ctx,
+ const void *key, size_t len)
+{
+ ctx->vtable = &br_aes_ct64_ctr_vtable;
+ ctx->num_rounds = br_aes_ct64_keysched(ctx->skey, key, len);
+}
+
+static void
+xorbuf(void *dst, const void *src, size_t len)
+{
+ unsigned char *d;
+ const unsigned char *s;
+
+ d = dst;
+ s = src;
+ while (len -- > 0) {
+ *d ++ ^= *s ++;
+ }
+}
+
+/* see bearssl_block.h */
+uint32_t
+br_aes_ct64_ctr_run(const br_aes_ct64_ctr_keys *ctx,
+ const void *iv, uint32_t cc, void *data, size_t len)
+{
+ unsigned char *buf;
+ uint32_t ivw[16];
+ uint64_t sk_exp[240];
+
+ br_aes_ct64_skey_expand(sk_exp, ctx->num_rounds, ctx->skey);
+ br_range_dec32le(ivw, 3, iv);
+ memcpy(ivw + 4, ivw, 3 * sizeof(uint32_t));
+ memcpy(ivw + 8, ivw, 3 * sizeof(uint32_t));
+ memcpy(ivw + 12, ivw, 3 * sizeof(uint32_t));
+ buf = data;
+ while (len > 0) {
+ uint64_t q[8];
+ uint32_t w[16];
+ unsigned char tmp[64];
+ int i;
+
+ /*
+ * TODO: see if we can save on the first br_aes_ct64_ortho()
+ * call, since iv0/iv1/iv2 are constant for the whole run.
+ */
+ memcpy(w, ivw, sizeof ivw);
+ w[3] = br_swap32(cc);
+ w[7] = br_swap32(cc + 1);
+ w[11] = br_swap32(cc + 2);
+ w[15] = br_swap32(cc + 3);
+ for (i = 0; i < 4; i ++) {
+ br_aes_ct64_interleave_in(
+ &q[i], &q[i + 4], w + (i << 2));
+ }
+ br_aes_ct64_ortho(q);
+ br_aes_ct64_bitslice_encrypt(ctx->num_rounds, sk_exp, q);
+ br_aes_ct64_ortho(q);
+ for (i = 0; i < 4; i ++) {
+ br_aes_ct64_interleave_out(
+ w + (i << 2), q[i], q[i + 4]);
+ }
+ br_range_enc32le(tmp, w, 16);
+ if (len <= 64) {
+ xorbuf(buf, tmp, len);
+ cc += (uint32_t)len >> 4;
+ break;
+ }
+ xorbuf(buf, tmp, 64);
+ buf += 64;
+ len -= 64;
+ cc += 4;
+ }
+ return cc;
+}
+
+/* see bearssl_block.h */
+const br_block_ctr_class br_aes_ct64_ctr_vtable = {
+ sizeof(br_aes_ct64_ctr_keys),
+ 16,
+ 4,
+ (void (*)(const br_block_ctr_class **, const void *, size_t))
+ &br_aes_ct64_ctr_init,
+ (uint32_t (*)(const br_block_ctr_class *const *,
+ const void *, uint32_t, void *, size_t))
+ &br_aes_ct64_ctr_run
+};
--- /dev/null
+/*
+ * 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 inner.h */
+void
+br_aes_ct64_bitslice_invSbox(uint64_t *q)
+{
+ /*
+ * See br_aes_ct_bitslice_invSbox(). This is the natural extension
+ * to 64-bit registers.
+ */
+ uint64_t q0, q1, q2, q3, q4, q5, q6, q7;
+
+ q0 = ~q[0];
+ q1 = ~q[1];
+ q2 = q[2];
+ q3 = q[3];
+ q4 = q[4];
+ q5 = ~q[5];
+ q6 = ~q[6];
+ q7 = q[7];
+ q[7] = q1 ^ q4 ^ q6;
+ q[6] = q0 ^ q3 ^ q5;
+ q[5] = q7 ^ q2 ^ q4;
+ q[4] = q6 ^ q1 ^ q3;
+ q[3] = q5 ^ q0 ^ q2;
+ q[2] = q4 ^ q7 ^ q1;
+ q[1] = q3 ^ q6 ^ q0;
+ q[0] = q2 ^ q5 ^ q7;
+
+ br_aes_ct64_bitslice_Sbox(q);
+
+ q0 = ~q[0];
+ q1 = ~q[1];
+ q2 = q[2];
+ q3 = q[3];
+ q4 = q[4];
+ q5 = ~q[5];
+ q6 = ~q[6];
+ q7 = q[7];
+ q[7] = q1 ^ q4 ^ q6;
+ q[6] = q0 ^ q3 ^ q5;
+ q[5] = q7 ^ q2 ^ q4;
+ q[4] = q6 ^ q1 ^ q3;
+ q[3] = q5 ^ q0 ^ q2;
+ q[2] = q4 ^ q7 ^ q1;
+ q[1] = q3 ^ q6 ^ q0;
+ q[0] = q2 ^ q5 ^ q7;
+}
+
+static void
+add_round_key(uint64_t *q, const uint64_t *sk)
+{
+ int i;
+
+ for (i = 0; i < 8; i ++) {
+ q[i] ^= sk[i];
+ }
+}
+
+static void
+inv_shift_rows(uint64_t *q)
+{
+ int i;
+
+ for (i = 0; i < 8; i ++) {
+ uint64_t x;
+
+ x = q[i];
+ q[i] = (x & (uint64_t)0x000000000000FFFF)
+ | ((x & (uint64_t)0x000000000FFF0000) << 4)
+ | ((x & (uint64_t)0x00000000F0000000) >> 12)
+ | ((x & (uint64_t)0x000000FF00000000) << 8)
+ | ((x & (uint64_t)0x0000FF0000000000) >> 8)
+ | ((x & (uint64_t)0x000F000000000000) << 12)
+ | ((x & (uint64_t)0xFFF0000000000000) >> 4);
+ }
+}
+
+static inline uint64_t
+rotr32(uint64_t x)
+{
+ return (x << 32) | (x >> 32);
+}
+
+static void
+inv_mix_columns(uint64_t *q)
+{
+ uint64_t q0, q1, q2, q3, q4, q5, q6, q7;
+ uint64_t r0, r1, r2, r3, r4, r5, r6, r7;
+
+ q0 = q[0];
+ q1 = q[1];
+ q2 = q[2];
+ q3 = q[3];
+ q4 = q[4];
+ q5 = q[5];
+ q6 = q[6];
+ q7 = q[7];
+ r0 = (q0 >> 16) | (q0 << 48);
+ r1 = (q1 >> 16) | (q1 << 48);
+ r2 = (q2 >> 16) | (q2 << 48);
+ r3 = (q3 >> 16) | (q3 << 48);
+ r4 = (q4 >> 16) | (q4 << 48);
+ r5 = (q5 >> 16) | (q5 << 48);
+ r6 = (q6 >> 16) | (q6 << 48);
+ r7 = (q7 >> 16) | (q7 << 48);
+
+ q[0] = q5 ^ q6 ^ q7 ^ r0 ^ r5 ^ r7 ^ rotr32(q0 ^ q5 ^ q6 ^ r0 ^ r5);
+ q[1] = q0 ^ q5 ^ r0 ^ r1 ^ r5 ^ r6 ^ r7 ^ rotr32(q1 ^ q5 ^ q7 ^ r1 ^ r5 ^ r6);
+ q[2] = q0 ^ q1 ^ q6 ^ r1 ^ r2 ^ r6 ^ r7 ^ rotr32(q0 ^ q2 ^ q6 ^ r2 ^ r6 ^ r7);
+ q[3] = q0 ^ q1 ^ q2 ^ q5 ^ q6 ^ r0 ^ r2 ^ r3 ^ r5 ^ rotr32(q0 ^ q1 ^ q3 ^ q5 ^ q6 ^ q7 ^ r0 ^ r3 ^ r5 ^ r7);
+ q[4] = q1 ^ q2 ^ q3 ^ q5 ^ r1 ^ r3 ^ r4 ^ r5 ^ r6 ^ r7 ^ rotr32(q1 ^ q2 ^ q4 ^ q5 ^ q7 ^ r1 ^ r4 ^ r5 ^ r6);
+ q[5] = q2 ^ q3 ^ q4 ^ q6 ^ r2 ^ r4 ^ r5 ^ r6 ^ r7 ^ rotr32(q2 ^ q3 ^ q5 ^ q6 ^ r2 ^ r5 ^ r6 ^ r7);
+ q[6] = q3 ^ q4 ^ q5 ^ q7 ^ r3 ^ r5 ^ r6 ^ r7 ^ rotr32(q3 ^ q4 ^ q6 ^ q7 ^ r3 ^ r6 ^ r7);
+ q[7] = q4 ^ q5 ^ q6 ^ r4 ^ r6 ^ r7 ^ rotr32(q4 ^ q5 ^ q7 ^ r4 ^ r7);
+}
+
+/* see inner.h */
+void
+br_aes_ct64_bitslice_decrypt(unsigned num_rounds,
+ const uint64_t *skey, uint64_t *q)
+{
+ unsigned u;
+
+ add_round_key(q, skey + (num_rounds << 3));
+ for (u = num_rounds - 1; u > 0; u --) {
+ inv_shift_rows(q);
+ br_aes_ct64_bitslice_invSbox(q);
+ add_round_key(q, skey + (u << 3));
+ inv_mix_columns(q);
+ }
+ inv_shift_rows(q);
+ br_aes_ct64_bitslice_invSbox(q);
+ add_round_key(q, skey);
+}
--- /dev/null
+/*
+ * 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"
+
+static inline void
+add_round_key(uint64_t *q, const uint64_t *sk)
+{
+ q[0] ^= sk[0];
+ q[1] ^= sk[1];
+ q[2] ^= sk[2];
+ q[3] ^= sk[3];
+ q[4] ^= sk[4];
+ q[5] ^= sk[5];
+ q[6] ^= sk[6];
+ q[7] ^= sk[7];
+}
+
+static inline void
+shift_rows(uint64_t *q)
+{
+ int i;
+
+ for (i = 0; i < 8; i ++) {
+ uint64_t x;
+
+ x = q[i];
+ q[i] = (x & (uint64_t)0x000000000000FFFF)
+ | ((x & (uint64_t)0x00000000FFF00000) >> 4)
+ | ((x & (uint64_t)0x00000000000F0000) << 12)
+ | ((x & (uint64_t)0x0000FF0000000000) >> 8)
+ | ((x & (uint64_t)0x000000FF00000000) << 8)
+ | ((x & (uint64_t)0xF000000000000000) >> 12)
+ | ((x & (uint64_t)0x0FFF000000000000) << 4);
+ }
+}
+
+static inline uint64_t
+rotr32(uint64_t x)
+{
+ return (x << 32) | (x >> 32);
+}
+
+static inline void
+mix_columns(uint64_t *q)
+{
+ uint64_t q0, q1, q2, q3, q4, q5, q6, q7;
+ uint64_t r0, r1, r2, r3, r4, r5, r6, r7;
+
+ q0 = q[0];
+ q1 = q[1];
+ q2 = q[2];
+ q3 = q[3];
+ q4 = q[4];
+ q5 = q[5];
+ q6 = q[6];
+ q7 = q[7];
+ r0 = (q0 >> 16) | (q0 << 48);
+ r1 = (q1 >> 16) | (q1 << 48);
+ r2 = (q2 >> 16) | (q2 << 48);
+ r3 = (q3 >> 16) | (q3 << 48);
+ r4 = (q4 >> 16) | (q4 << 48);
+ r5 = (q5 >> 16) | (q5 << 48);
+ r6 = (q6 >> 16) | (q6 << 48);
+ r7 = (q7 >> 16) | (q7 << 48);
+
+ q[0] = q7 ^ r7 ^ r0 ^ rotr32(q0 ^ r0);
+ q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr32(q1 ^ r1);
+ q[2] = q1 ^ r1 ^ r2 ^ rotr32(q2 ^ r2);
+ q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr32(q3 ^ r3);
+ q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr32(q4 ^ r4);
+ q[5] = q4 ^ r4 ^ r5 ^ rotr32(q5 ^ r5);
+ q[6] = q5 ^ r5 ^ r6 ^ rotr32(q6 ^ r6);
+ q[7] = q6 ^ r6 ^ r7 ^ rotr32(q7 ^ r7);
+}
+
+/* see inner.h */
+void
+br_aes_ct64_bitslice_encrypt(unsigned num_rounds,
+ const uint64_t *skey, uint64_t *q)
+{
+ unsigned u;
+
+ add_round_key(q, skey);
+ for (u = 1; u < num_rounds; u ++) {
+ br_aes_ct64_bitslice_Sbox(q);
+ shift_rows(q);
+ mix_columns(q);
+ add_round_key(q, skey + (u << 3));
+ }
+ br_aes_ct64_bitslice_Sbox(q);
+ shift_rows(q);
+ add_round_key(q, skey + (num_rounds << 3));
+}
--- /dev/null
+/*
+ * 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_block.h */
+void
+br_aes_ct_cbcdec_init(br_aes_ct_cbcdec_keys *ctx,
+ const void *key, size_t len)
+{
+ ctx->vtable = &br_aes_ct_cbcdec_vtable;
+ ctx->num_rounds = br_aes_ct_keysched(ctx->skey, key, len);
+}
+
+/* see bearssl_block.h */
+void
+br_aes_ct_cbcdec_run(const br_aes_ct_cbcdec_keys *ctx,
+ void *iv, void *data, size_t len)
+{
+ unsigned char *buf, *ivbuf;
+ uint32_t iv0, iv1, iv2, iv3;
+ uint32_t sk_exp[120];
+
+ br_aes_ct_skey_expand(sk_exp, ctx->num_rounds, ctx->skey);
+ ivbuf = iv;
+ iv0 = br_dec32le(ivbuf);
+ iv1 = br_dec32le(ivbuf + 4);
+ iv2 = br_dec32le(ivbuf + 8);
+ iv3 = br_dec32le(ivbuf + 12);
+ buf = data;
+ while (len > 0) {
+ uint32_t q[8], sq[8];
+
+ q[0] = br_dec32le(buf);
+ q[2] = br_dec32le(buf + 4);
+ q[4] = br_dec32le(buf + 8);
+ q[6] = br_dec32le(buf + 12);
+ if (len >= 32) {
+ q[1] = br_dec32le(buf + 16);
+ q[3] = br_dec32le(buf + 20);
+ q[5] = br_dec32le(buf + 24);
+ q[7] = br_dec32le(buf + 28);
+ } else {
+ q[1] = 0;
+ q[3] = 0;
+ q[5] = 0;
+ q[7] = 0;
+ }
+ memcpy(sq, q, sizeof q);
+ br_aes_ct_ortho(q);
+ br_aes_ct_bitslice_decrypt(ctx->num_rounds, sk_exp, q);
+ br_aes_ct_ortho(q);
+ br_enc32le(buf, q[0] ^ iv0);
+ br_enc32le(buf + 4, q[2] ^ iv1);
+ br_enc32le(buf + 8, q[4] ^ iv2);
+ br_enc32le(buf + 12, q[6] ^ iv3);
+ if (len < 32) {
+ iv0 = sq[0];
+ iv1 = sq[2];
+ iv2 = sq[4];
+ iv3 = sq[6];
+ break;
+ }
+ br_enc32le(buf + 16, q[1] ^ sq[0]);
+ br_enc32le(buf + 20, q[3] ^ sq[2]);
+ br_enc32le(buf + 24, q[5] ^ sq[4]);
+ br_enc32le(buf + 28, q[7] ^ sq[6]);
+ iv0 = sq[1];
+ iv1 = sq[3];
+ iv2 = sq[5];
+ iv3 = sq[7];
+ buf += 32;
+ len -= 32;
+ }
+ br_enc32le(ivbuf, iv0);
+ br_enc32le(ivbuf + 4, iv1);
+ br_enc32le(ivbuf + 8, iv2);
+ br_enc32le(ivbuf + 12, iv3);
+}
+
+/* see bearssl_block.h */
+const br_block_cbcdec_class br_aes_ct_cbcdec_vtable = {
+ sizeof(br_aes_ct_cbcdec_keys),
+ 16,
+ 4,
+ (void (*)(const br_block_cbcdec_class **, const void *, size_t))
+ &br_aes_ct_cbcdec_init,
+ (void (*)(const br_block_cbcdec_class *const *, void *, void *, size_t))
+ &br_aes_ct_cbcdec_run
+};
--- /dev/null
+/*
+ * 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_block.h */
+void
+br_aes_ct_cbcenc_init(br_aes_ct_cbcenc_keys *ctx,
+ const void *key, size_t len)
+{
+ ctx->vtable = &br_aes_ct_cbcenc_vtable;
+ ctx->num_rounds = br_aes_ct_keysched(ctx->skey, key, len);
+}
+
+/* see bearssl_block.h */
+void
+br_aes_ct_cbcenc_run(const br_aes_ct_cbcenc_keys *ctx,
+ void *iv, void *data, size_t len)
+{
+ unsigned char *buf, *ivbuf;
+ uint32_t q[8];
+ uint32_t iv0, iv1, iv2, iv3;
+ uint32_t sk_exp[120];
+
+ q[1] = 0;
+ q[3] = 0;
+ q[5] = 0;
+ q[7] = 0;
+ br_aes_ct_skey_expand(sk_exp, ctx->num_rounds, ctx->skey);
+ ivbuf = iv;
+ iv0 = br_dec32le(ivbuf);
+ iv1 = br_dec32le(ivbuf + 4);
+ iv2 = br_dec32le(ivbuf + 8);
+ iv3 = br_dec32le(ivbuf + 12);
+ buf = data;
+ while (len > 0) {
+ q[0] = iv0 ^ br_dec32le(buf);
+ q[2] = iv1 ^ br_dec32le(buf + 4);
+ q[4] = iv2 ^ br_dec32le(buf + 8);
+ q[6] = iv3 ^ br_dec32le(buf + 12);
+ br_aes_ct_ortho(q);
+ br_aes_ct_bitslice_encrypt(ctx->num_rounds, sk_exp, q);
+ br_aes_ct_ortho(q);
+ iv0 = q[0];
+ iv1 = q[2];
+ iv2 = q[4];
+ iv3 = q[6];
+ br_enc32le(buf, iv0);
+ br_enc32le(buf + 4, iv1);
+ br_enc32le(buf + 8, iv2);
+ br_enc32le(buf + 12, iv3);
+ buf += 16;
+ len -= 16;
+ }
+ br_enc32le(ivbuf, iv0);
+ br_enc32le(ivbuf + 4, iv1);
+ br_enc32le(ivbuf + 8, iv2);
+ br_enc32le(ivbuf + 12, iv3);
+}
+
+/* see bearssl_block.h */
+const br_block_cbcenc_class br_aes_ct_cbcenc_vtable = {
+ sizeof(br_aes_ct_cbcenc_keys),
+ 16,
+ 4,
+ (void (*)(const br_block_cbcenc_class **, const void *, size_t))
+ &br_aes_ct_cbcenc_init,
+ (void (*)(const br_block_cbcenc_class *const *, void *, void *, size_t))
+ &br_aes_ct_cbcenc_run
+};
--- /dev/null
+/*
+ * 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_block.h */
+void
+br_aes_ct_ctr_init(br_aes_ct_ctr_keys *ctx,
+ const void *key, size_t len)
+{
+ ctx->vtable = &br_aes_ct_ctr_vtable;
+ ctx->num_rounds = br_aes_ct_keysched(ctx->skey, key, len);
+}
+
+static void
+xorbuf(void *dst, const void *src, size_t len)
+{
+ unsigned char *d;
+ const unsigned char *s;
+
+ d = dst;
+ s = src;
+ while (len -- > 0) {
+ *d ++ ^= *s ++;
+ }
+}
+
+/* see bearssl_block.h */
+uint32_t
+br_aes_ct_ctr_run(const br_aes_ct_ctr_keys *ctx,
+ const void *iv, uint32_t cc, void *data, size_t len)
+{
+ unsigned char *buf;
+ const unsigned char *ivbuf;
+ uint32_t iv0, iv1, iv2;
+ uint32_t sk_exp[120];
+
+ br_aes_ct_skey_expand(sk_exp, ctx->num_rounds, ctx->skey);
+ ivbuf = iv;
+ iv0 = br_dec32le(ivbuf);
+ iv1 = br_dec32le(ivbuf + 4);
+ iv2 = br_dec32le(ivbuf + 8);
+ buf = data;
+ while (len > 0) {
+ uint32_t q[8];
+ unsigned char tmp[32];
+
+ /*
+ * TODO: see if we can save on the first br_aes_ct_ortho()
+ * call, since iv0/iv1/iv2 are constant for the whole run.
+ */
+ q[0] = q[1] = iv0;
+ q[2] = q[3] = iv1;
+ q[4] = q[5] = iv2;
+ q[6] = br_swap32(cc);
+ q[7] = br_swap32(cc + 1);
+ br_aes_ct_ortho(q);
+ br_aes_ct_bitslice_encrypt(ctx->num_rounds, sk_exp, q);
+ br_aes_ct_ortho(q);
+ br_enc32le(tmp, q[0]);
+ br_enc32le(tmp + 4, q[2]);
+ br_enc32le(tmp + 8, q[4]);
+ br_enc32le(tmp + 12, q[6]);
+ br_enc32le(tmp + 16, q[1]);
+ br_enc32le(tmp + 20, q[3]);
+ br_enc32le(tmp + 24, q[5]);
+ br_enc32le(tmp + 28, q[7]);
+
+ if (len <= 32) {
+ xorbuf(buf, tmp, len);
+ cc ++;
+ if (len > 16) {
+ cc ++;
+ }
+ break;
+ }
+ xorbuf(buf, tmp, 32);
+ buf += 32;
+ len -= 32;
+ cc += 2;
+ }
+ return cc;
+}
+
+/* see bearssl_block.h */
+const br_block_ctr_class br_aes_ct_ctr_vtable = {
+ sizeof(br_aes_ct_ctr_keys),
+ 16,
+ 4,
+ (void (*)(const br_block_ctr_class **, const void *, size_t))
+ &br_aes_ct_ctr_init,
+ (uint32_t (*)(const br_block_ctr_class *const *,
+ const void *, uint32_t, void *, size_t))
+ &br_aes_ct_ctr_run
+};
--- /dev/null
+/*
+ * 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 inner.h */
+void
+br_aes_ct_bitslice_invSbox(uint32_t *q)
+{
+ /*
+ * AES S-box is:
+ * S(x) = A(I(x)) ^ 0x63
+ * where I() is inversion in GF(256), and A() is a linear
+ * transform (0 is formally defined to be its own inverse).
+ * Since inversion is an involution, the inverse S-box can be
+ * computed from the S-box as:
+ * iS(x) = B(S(B(x ^ 0x63)) ^ 0x63)
+ * where B() is the inverse of A(). Indeed, for any y in GF(256):
+ * iS(S(y)) = B(A(I(B(A(I(y)) ^ 0x63 ^ 0x63))) ^ 0x63 ^ 0x63) = y
+ *
+ * Note: we reuse the implementation of the forward S-box,
+ * instead of duplicating it here, so that total code size is
+ * lower. By merging the B() transforms into the S-box circuit
+ * we could make faster CBC decryption, but CBC decryption is
+ * already quite faster than CBC encryption because we can
+ * process two blocks in parallel.
+ */
+ uint32_t q0, q1, q2, q3, q4, q5, q6, q7;
+
+ q0 = ~q[0];
+ q1 = ~q[1];
+ q2 = q[2];
+ q3 = q[3];
+ q4 = q[4];
+ q5 = ~q[5];
+ q6 = ~q[6];
+ q7 = q[7];
+ q[7] = q1 ^ q4 ^ q6;
+ q[6] = q0 ^ q3 ^ q5;
+ q[5] = q7 ^ q2 ^ q4;
+ q[4] = q6 ^ q1 ^ q3;
+ q[3] = q5 ^ q0 ^ q2;
+ q[2] = q4 ^ q7 ^ q1;
+ q[1] = q3 ^ q6 ^ q0;
+ q[0] = q2 ^ q5 ^ q7;
+
+ br_aes_ct_bitslice_Sbox(q);
+
+ q0 = ~q[0];
+ q1 = ~q[1];
+ q2 = q[2];
+ q3 = q[3];
+ q4 = q[4];
+ q5 = ~q[5];
+ q6 = ~q[6];
+ q7 = q[7];
+ q[7] = q1 ^ q4 ^ q6;
+ q[6] = q0 ^ q3 ^ q5;
+ q[5] = q7 ^ q2 ^ q4;
+ q[4] = q6 ^ q1 ^ q3;
+ q[3] = q5 ^ q0 ^ q2;
+ q[2] = q4 ^ q7 ^ q1;
+ q[1] = q3 ^ q6 ^ q0;
+ q[0] = q2 ^ q5 ^ q7;
+}
+
+static void
+add_round_key(uint32_t *q, const uint32_t *sk)
+{
+ int i;
+
+ for (i = 0; i < 8; i ++) {
+ q[i] ^= sk[i];
+ }
+}
+
+static void
+inv_shift_rows(uint32_t *q)
+{
+ int i;
+
+ for (i = 0; i < 8; i ++) {
+ uint32_t x;
+
+ x = q[i];
+ q[i] = (x & 0x000000FF)
+ | ((x & 0x00003F00) << 2) | ((x & 0x0000C000) >> 6)
+ | ((x & 0x000F0000) << 4) | ((x & 0x00F00000) >> 4)
+ | ((x & 0x03000000) << 6) | ((x & 0xFC000000) >> 2);
+ }
+}
+
+static inline uint32_t
+rotr16(uint32_t x)
+{
+ return (x << 16) | (x >> 16);
+}
+
+static void
+inv_mix_columns(uint32_t *q)
+{
+ uint32_t q0, q1, q2, q3, q4, q5, q6, q7;
+ uint32_t r0, r1, r2, r3, r4, r5, r6, r7;
+
+ q0 = q[0];
+ q1 = q[1];
+ q2 = q[2];
+ q3 = q[3];
+ q4 = q[4];
+ q5 = q[5];
+ q6 = q[6];
+ q7 = q[7];
+ r0 = (q0 >> 8) | (q0 << 24);
+ r1 = (q1 >> 8) | (q1 << 24);
+ r2 = (q2 >> 8) | (q2 << 24);
+ r3 = (q3 >> 8) | (q3 << 24);
+ r4 = (q4 >> 8) | (q4 << 24);
+ r5 = (q5 >> 8) | (q5 << 24);
+ r6 = (q6 >> 8) | (q6 << 24);
+ r7 = (q7 >> 8) | (q7 << 24);
+
+ q[0] = q5 ^ q6 ^ q7 ^ r0 ^ r5 ^ r7 ^ rotr16(q0 ^ q5 ^ q6 ^ r0 ^ r5);
+ q[1] = q0 ^ q5 ^ r0 ^ r1 ^ r5 ^ r6 ^ r7 ^ rotr16(q1 ^ q5 ^ q7 ^ r1 ^ r5 ^ r6);
+ q[2] = q0 ^ q1 ^ q6 ^ r1 ^ r2 ^ r6 ^ r7 ^ rotr16(q0 ^ q2 ^ q6 ^ r2 ^ r6 ^ r7);
+ q[3] = q0 ^ q1 ^ q2 ^ q5 ^ q6 ^ r0 ^ r2 ^ r3 ^ r5 ^ rotr16(q0 ^ q1 ^ q3 ^ q5 ^ q6 ^ q7 ^ r0 ^ r3 ^ r5 ^ r7);
+ q[4] = q1 ^ q2 ^ q3 ^ q5 ^ r1 ^ r3 ^ r4 ^ r5 ^ r6 ^ r7 ^ rotr16(q1 ^ q2 ^ q4 ^ q5 ^ q7 ^ r1 ^ r4 ^ r5 ^ r6);
+ q[5] = q2 ^ q3 ^ q4 ^ q6 ^ r2 ^ r4 ^ r5 ^ r6 ^ r7 ^ rotr16(q2 ^ q3 ^ q5 ^ q6 ^ r2 ^ r5 ^ r6 ^ r7);
+ q[6] = q3 ^ q4 ^ q5 ^ q7 ^ r3 ^ r5 ^ r6 ^ r7 ^ rotr16(q3 ^ q4 ^ q6 ^ q7 ^ r3 ^ r6 ^ r7);
+ q[7] = q4 ^ q5 ^ q6 ^ r4 ^ r6 ^ r7 ^ rotr16(q4 ^ q5 ^ q7 ^ r4 ^ r7);
+}
+
+/* see inner.h */
+void
+br_aes_ct_bitslice_decrypt(unsigned num_rounds,
+ const uint32_t *skey, uint32_t *q)
+{
+ unsigned u;
+
+ add_round_key(q, skey + (num_rounds << 3));
+ for (u = num_rounds - 1; u > 0; u --) {
+ inv_shift_rows(q);
+ br_aes_ct_bitslice_invSbox(q);
+ add_round_key(q, skey + (u << 3));
+ inv_mix_columns(q);
+ }
+ inv_shift_rows(q);
+ br_aes_ct_bitslice_invSbox(q);
+ add_round_key(q, skey);
+}
--- /dev/null
+/*
+ * 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"
+
+static inline void
+add_round_key(uint32_t *q, const uint32_t *sk)
+{
+ q[0] ^= sk[0];
+ q[1] ^= sk[1];
+ q[2] ^= sk[2];
+ q[3] ^= sk[3];
+ q[4] ^= sk[4];
+ q[5] ^= sk[5];
+ q[6] ^= sk[6];
+ q[7] ^= sk[7];
+}
+
+static inline void
+shift_rows(uint32_t *q)
+{
+ int i;
+
+ for (i = 0; i < 8; i ++) {
+ uint32_t x;
+
+ x = q[i];
+ q[i] = (x & 0x000000FF)
+ | ((x & 0x0000FC00) >> 2) | ((x & 0x00000300) << 6)
+ | ((x & 0x00F00000) >> 4) | ((x & 0x000F0000) << 4)
+ | ((x & 0xC0000000) >> 6) | ((x & 0x3F000000) << 2);
+ }
+}
+
+static inline uint32_t
+rotr16(uint32_t x)
+{
+ return (x << 16) | (x >> 16);
+}
+
+static inline void
+mix_columns(uint32_t *q)
+{
+ uint32_t q0, q1, q2, q3, q4, q5, q6, q7;
+ uint32_t r0, r1, r2, r3, r4, r5, r6, r7;
+
+ q0 = q[0];
+ q1 = q[1];
+ q2 = q[2];
+ q3 = q[3];
+ q4 = q[4];
+ q5 = q[5];
+ q6 = q[6];
+ q7 = q[7];
+ r0 = (q0 >> 8) | (q0 << 24);
+ r1 = (q1 >> 8) | (q1 << 24);
+ r2 = (q2 >> 8) | (q2 << 24);
+ r3 = (q3 >> 8) | (q3 << 24);
+ r4 = (q4 >> 8) | (q4 << 24);
+ r5 = (q5 >> 8) | (q5 << 24);
+ r6 = (q6 >> 8) | (q6 << 24);
+ r7 = (q7 >> 8) | (q7 << 24);
+
+ q[0] = q7 ^ r7 ^ r0 ^ rotr16(q0 ^ r0);
+ q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr16(q1 ^ r1);
+ q[2] = q1 ^ r1 ^ r2 ^ rotr16(q2 ^ r2);
+ q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr16(q3 ^ r3);
+ q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr16(q4 ^ r4);
+ q[5] = q4 ^ r4 ^ r5 ^ rotr16(q5 ^ r5);
+ q[6] = q5 ^ r5 ^ r6 ^ rotr16(q6 ^ r6);
+ q[7] = q6 ^ r6 ^ r7 ^ rotr16(q7 ^ r7);
+}
+
+/* see inner.h */
+void
+br_aes_ct_bitslice_encrypt(unsigned num_rounds,
+ const uint32_t *skey, uint32_t *q)
+{
+ unsigned u;
+
+ add_round_key(q, skey);
+ for (u = 1; u < num_rounds; u ++) {
+ br_aes_ct_bitslice_Sbox(q);
+ shift_rows(q);
+ mix_columns(q);
+ add_round_key(q, skey + (u << 3));
+ }
+ br_aes_ct_bitslice_Sbox(q);
+ shift_rows(q);
+ add_round_key(q, skey + (num_rounds << 3));
+}
--- /dev/null
+/*
+ * 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_block.h */
+void
+br_aes_small_cbcdec_init(br_aes_small_cbcdec_keys *ctx,
+ const void *key, size_t len)
+{
+ ctx->vtable = &br_aes_small_cbcdec_vtable;
+ ctx->num_rounds = br_aes_keysched(ctx->skey, key, len);
+}
+
+/* see bearssl_block.h */
+void
+br_aes_small_cbcdec_run(const br_aes_small_cbcdec_keys *ctx,
+ void *iv, void *data, size_t len)
+{
+ unsigned char *buf, *ivbuf;
+
+ ivbuf = iv;
+ buf = data;
+ while (len > 0) {
+ unsigned char tmp[16];
+ int i;
+
+ memcpy(tmp, buf, 16);
+ br_aes_small_decrypt(ctx->num_rounds, ctx->skey, buf);
+ for (i = 0; i < 16; i ++) {
+ buf[i] ^= ivbuf[i];
+ }
+ memcpy(ivbuf, tmp, 16);
+ buf += 16;
+ len -= 16;
+ }
+}
+
+/* see bearssl_block.h */
+const br_block_cbcdec_class br_aes_small_cbcdec_vtable = {
+ sizeof(br_aes_small_cbcdec_keys),
+ 16,
+ 4,
+ (void (*)(const br_block_cbcdec_class **, const void *, size_t))
+ &br_aes_small_cbcdec_init,
+ (void (*)(const br_block_cbcdec_class *const *, void *, void *, size_t))
+ &br_aes_small_cbcdec_run
+};
--- /dev/null
+/*
+ * 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_block.h */
+void
+br_aes_small_cbcenc_init(br_aes_small_cbcenc_keys *ctx,
+ const void *key, size_t len)
+{
+ ctx->vtable = &br_aes_small_cbcenc_vtable;
+ ctx->num_rounds = br_aes_keysched(ctx->skey, key, len);
+}
+
+/* see bearssl_block.h */
+void
+br_aes_small_cbcenc_run(const br_aes_small_cbcenc_keys *ctx,
+ void *iv, void *data, size_t len)
+{
+ unsigned char *buf, *ivbuf;
+
+ ivbuf = iv;
+ buf = data;
+ while (len > 0) {
+ int i;
+
+ for (i = 0; i < 16; i ++) {
+ buf[i] ^= ivbuf[i];
+ }
+ br_aes_small_encrypt(ctx->num_rounds, ctx->skey, buf);
+ memcpy(ivbuf, buf, 16);
+ buf += 16;
+ len -= 16;
+ }
+}
+
+/* see bearssl_block.h */
+const br_block_cbcenc_class br_aes_small_cbcenc_vtable = {
+ sizeof(br_aes_small_cbcenc_keys),
+ 16,
+ 4,
+ (void (*)(const br_block_cbcenc_class **, const void *, size_t))
+ &br_aes_small_cbcenc_init,
+ (void (*)(const br_block_cbcenc_class *const *, void *, void *, size_t))
+ &br_aes_small_cbcenc_run
+};
--- /dev/null
+/*
+ * 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_block.h */
+void
+br_aes_small_ctr_init(br_aes_small_ctr_keys *ctx,
+ const void *key, size_t len)
+{
+ ctx->vtable = &br_aes_small_ctr_vtable;
+ ctx->num_rounds = br_aes_keysched(ctx->skey, key, len);
+}
+
+static void
+xorbuf(void *dst, const void *src, size_t len)
+{
+ unsigned char *d;
+ const unsigned char *s;
+
+ d = dst;
+ s = src;
+ while (len -- > 0) {
+ *d ++ ^= *s ++;
+ }
+}
+
+/* see bearssl_block.h */
+uint32_t
+br_aes_small_ctr_run(const br_aes_small_ctr_keys *ctx,
+ const void *iv, uint32_t cc, void *data, size_t len)
+{
+ unsigned char *buf;
+
+ buf = data;
+ while (len > 0) {
+ unsigned char tmp[16];
+
+ memcpy(tmp, iv, 12);
+ br_enc32be(tmp + 12, cc ++);
+ br_aes_small_encrypt(ctx->num_rounds, ctx->skey, tmp);
+ if (len <= 16) {
+ xorbuf(buf, tmp, len);
+ break;
+ }
+ xorbuf(buf, tmp, 16);
+ buf += 16;
+ len -= 16;
+ }
+ return cc;
+}
+
+/* see bearssl_block.h */
+const br_block_ctr_class br_aes_small_ctr_vtable = {
+ sizeof(br_aes_small_ctr_keys),
+ 16,
+ 4,
+ (void (*)(const br_block_ctr_class **, const void *, size_t))
+ &br_aes_small_ctr_init,
+ (uint32_t (*)(const br_block_ctr_class *const *,
+ const void *, uint32_t, void *, size_t))
+ &br_aes_small_ctr_run
+};
--- /dev/null
+/*
+ * 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"
+
+/*
+ * Inverse S-box.
+ */
+static const unsigned char iS[] = {
+ 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E,
+ 0x81, 0xF3, 0xD7, 0xFB, 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87,
+ 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, 0x54, 0x7B, 0x94, 0x32,
+ 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
+ 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49,
+ 0x6D, 0x8B, 0xD1, 0x25, 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16,
+ 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, 0x6C, 0x70, 0x48, 0x50,
+ 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
+ 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05,
+ 0xB8, 0xB3, 0x45, 0x06, 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02,
+ 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, 0x3A, 0x91, 0x11, 0x41,
+ 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
+ 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8,
+ 0x1C, 0x75, 0xDF, 0x6E, 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89,
+ 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, 0xFC, 0x56, 0x3E, 0x4B,
+ 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
+ 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59,
+ 0x27, 0x80, 0xEC, 0x5F, 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D,
+ 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, 0xA0, 0xE0, 0x3B, 0x4D,
+ 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
+ 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63,
+ 0x55, 0x21, 0x0C, 0x7D
+};
+
+static void
+add_round_key(unsigned *state, const uint32_t *skeys)
+{
+ int i;
+
+ for (i = 0; i < 16; i += 4) {
+ uint32_t k;
+
+ k = *skeys ++;
+ state[i + 0] ^= (unsigned)(k >> 24);
+ state[i + 1] ^= (unsigned)(k >> 16) & 0xFF;
+ state[i + 2] ^= (unsigned)(k >> 8) & 0xFF;
+ state[i + 3] ^= (unsigned)k & 0xFF;
+ }
+}
+
+static void
+inv_sub_bytes(unsigned *state)
+{
+ int i;
+
+ for (i = 0; i < 16; i ++) {
+ state[i] = iS[state[i]];
+ }
+}
+
+static void
+inv_shift_rows(unsigned *state)
+{
+ unsigned tmp;
+
+ tmp = state[13];
+ state[13] = state[9];
+ state[9] = state[5];
+ state[5] = state[1];
+ state[1] = tmp;
+
+ tmp = state[2];
+ state[2] = state[10];
+ state[10] = tmp;
+ tmp = state[6];
+ state[6] = state[14];
+ state[14] = tmp;
+
+ tmp = state[3];
+ state[3] = state[7];
+ state[7] = state[11];
+ state[11] = state[15];
+ state[15] = tmp;
+}
+
+static inline unsigned
+gf256red(unsigned x)
+{
+ unsigned y;
+
+ y = x >> 8;
+ return (x ^ y ^ (y << 1) ^ (y << 3) ^ (y << 4)) & 0xFF;
+}
+
+static void
+inv_mix_columns(unsigned *state)
+{
+ int i;
+
+ for (i = 0; i < 16; i += 4) {
+ unsigned s0, s1, s2, s3;
+ unsigned t0, t1, t2, t3;
+
+ s0 = state[i + 0];
+ s1 = state[i + 1];
+ s2 = state[i + 2];
+ s3 = state[i + 3];
+ t0 = (s0 << 1) ^ (s0 << 2) ^ (s0 << 3)
+ ^ s1 ^ (s1 << 1) ^ (s1 << 3)
+ ^ s2 ^ (s2 << 2) ^ (s2 << 3)
+ ^ s3 ^ (s3 << 3);
+ t1 = s0 ^ (s0 << 3)
+ ^ (s1 << 1) ^ (s1 << 2) ^ (s1 << 3)
+ ^ s2 ^ (s2 << 1) ^ (s2 << 3)
+ ^ s3 ^ (s3 << 2) ^ (s3 << 3);
+ t2 = s0 ^ (s0 << 2) ^ (s0 << 3)
+ ^ s1 ^ (s1 << 3)
+ ^ (s2 << 1) ^ (s2 << 2) ^ (s2 << 3)
+ ^ s3 ^ (s3 << 1) ^ (s3 << 3);
+ t3 = s0 ^ (s0 << 1) ^ (s0 << 3)
+ ^ s1 ^ (s1 << 2) ^ (s1 << 3)
+ ^ s2 ^ (s2 << 3)
+ ^ (s3 << 1) ^ (s3 << 2) ^ (s3 << 3);
+ state[i + 0] = gf256red(t0);
+ state[i + 1] = gf256red(t1);
+ state[i + 2] = gf256red(t2);
+ state[i + 3] = gf256red(t3);
+ }
+}
+
+/* see inner.h */
+void
+br_aes_small_decrypt(unsigned num_rounds, const uint32_t *skey, void *data)
+{
+ unsigned char *buf;
+ unsigned state[16];
+ unsigned u;
+
+ buf = data;
+ for (u = 0; u < 16; u ++) {
+ state[u] = buf[u];
+ }
+ add_round_key(state, skey + (num_rounds << 2));
+ for (u = num_rounds - 1; u > 0; u --) {
+ inv_shift_rows(state);
+ inv_sub_bytes(state);
+ add_round_key(state, skey + (u << 2));
+ inv_mix_columns(state);
+ }
+ inv_shift_rows(state);
+ inv_sub_bytes(state);
+ add_round_key(state, skey);
+ for (u = 0; u < 16; u ++) {
+ buf[u] = state[u];
+ }
+}
--- /dev/null
+/*
+ * 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"
+
+#define S br_aes_S
+
+static void
+add_round_key(unsigned *state, const uint32_t *skeys)
+{
+ int i;
+
+ for (i = 0; i < 16; i += 4) {
+ uint32_t k;
+
+ k = *skeys ++;
+ state[i + 0] ^= (unsigned)(k >> 24);
+ state[i + 1] ^= (unsigned)(k >> 16) & 0xFF;
+ state[i + 2] ^= (unsigned)(k >> 8) & 0xFF;
+ state[i + 3] ^= (unsigned)k & 0xFF;
+ }
+}
+
+static void
+sub_bytes(unsigned *state)
+{
+ int i;
+
+ for (i = 0; i < 16; i ++) {
+ state[i] = S[state[i]];
+ }
+}
+
+static void
+shift_rows(unsigned *state)
+{
+ unsigned tmp;
+
+ tmp = state[1];
+ state[1] = state[5];
+ state[5] = state[9];
+ state[9] = state[13];
+ state[13] = tmp;
+
+ tmp = state[2];
+ state[2] = state[10];
+ state[10] = tmp;
+ tmp = state[6];
+ state[6] = state[14];
+ state[14] = tmp;
+
+ tmp = state[15];
+ state[15] = state[11];
+ state[11] = state[7];
+ state[7] = state[3];
+ state[3] = tmp;
+}
+
+static void
+mix_columns(unsigned *state)
+{
+ int i;
+
+ for (i = 0; i < 16; i += 4) {
+ unsigned s0, s1, s2, s3;
+ unsigned t0, t1, t2, t3;
+
+ s0 = state[i + 0];
+ s1 = state[i + 1];
+ s2 = state[i + 2];
+ s3 = state[i + 3];
+ t0 = (s0 << 1) ^ s1 ^ (s1 << 1) ^ s2 ^ s3;
+ t1 = s0 ^ (s1 << 1) ^ s2 ^ (s2 << 1) ^ s3;
+ t2 = s0 ^ s1 ^ (s2 << 1) ^ s3 ^ (s3 << 1);
+ t3 = s0 ^ (s0 << 1) ^ s1 ^ s2 ^ (s3 << 1);
+ state[i + 0] = t0 ^ ((unsigned)(-(int)(t0 >> 8)) & 0x11B);
+ state[i + 1] = t1 ^ ((unsigned)(-(int)(t1 >> 8)) & 0x11B);
+ state[i + 2] = t2 ^ ((unsigned)(-(int)(t2 >> 8)) & 0x11B);
+ state[i + 3] = t3 ^ ((unsigned)(-(int)(t3 >> 8)) & 0x11B);
+ }
+}
+
+/* see inner.h */
+void
+br_aes_small_encrypt(unsigned num_rounds, const uint32_t *skey, void *data)
+{
+ unsigned char *buf;
+ unsigned state[16];
+ unsigned u;
+
+ buf = data;
+ for (u = 0; u < 16; u ++) {
+ state[u] = buf[u];
+ }
+ add_round_key(state, skey);
+ for (u = 1; u < num_rounds; u ++) {
+ sub_bytes(state);
+ shift_rows(state);
+ mix_columns(state);
+ add_round_key(state, skey + (u << 2));
+ }
+ sub_bytes(state);
+ shift_rows(state);
+ add_round_key(state, skey + (num_rounds << 2));
+ for (u = 0; u < 16; u ++) {
+ buf[u] = state[u];
+ }
+}
--- /dev/null
+/*
+ * 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"
+
+/*
+ * During key schedule, we need to apply bit extraction PC-2 then permute
+ * things into our bitslice representation. PC-2 extracts 48 bits out
+ * of two 28-bit words (kl and kr), and we store these bits into two
+ * 32-bit words sk0 and sk1.
+ *
+ * -- bit 16+x of sk0 comes from bit QL0[x] of kl
+ * -- bit x of sk0 comes from bit QR0[x] of kr
+ * -- bit 16+x of sk1 comes from bit QL1[x] of kl
+ * -- bit x of sk1 comes from bit QR1[x] of kr
+ */
+
+static const unsigned char QL0[] = {
+ 17, 4, 27, 23, 13, 22, 7, 18,
+ 16, 24, 2, 20, 1, 8, 15, 26
+};
+
+static const unsigned char QR0[] = {
+ 25, 19, 9, 1, 5, 11, 23, 8,
+ 17, 0, 22, 3, 6, 20, 27, 24
+};
+
+static const unsigned char QL1[] = {
+ 28, 28, 14, 11, 28, 28, 25, 0,
+ 28, 28, 5, 9, 28, 28, 12, 21
+};
+
+static const unsigned char QR1[] = {
+ 28, 28, 15, 4, 28, 28, 26, 16,
+ 28, 28, 12, 7, 28, 28, 10, 14
+};
+
+/*
+ * 32-bit rotation. The C compiler is supposed to recognize it as a
+ * rotation and use the local architecture rotation opcode (if available).
+ */
+static inline uint32_t
+rotl(uint32_t x, int n)
+{
+ return (x << n) | (x >> (32 - n));
+}
+
+/*
+ * Compute key schedule for 8 key bytes (produces 32 subkey words).
+ */
+static void
+keysched_unit(uint32_t *skey, const void *key)
+{
+ int i;
+
+ br_des_keysched_unit(skey, key);
+
+ /*
+ * Apply PC-2 + bitslicing.
+ */
+ for (i = 0; i < 16; i ++) {
+ uint32_t kl, kr, sk0, sk1;
+ int j;
+
+ kl = skey[(i << 1) + 0];
+ kr = skey[(i << 1) + 1];
+ sk0 = 0;
+ sk1 = 0;
+ for (j = 0; j < 16; j ++) {
+ sk0 <<= 1;
+ sk1 <<= 1;
+ sk0 |= ((kl >> QL0[j]) & (uint32_t)1) << 16;
+ sk0 |= (kr >> QR0[j]) & (uint32_t)1;
+ sk1 |= ((kl >> QL1[j]) & (uint32_t)1) << 16;
+ sk1 |= (kr >> QR1[j]) & (uint32_t)1;
+ }
+
+ skey[(i << 1) + 0] = sk0;
+ skey[(i << 1) + 1] = sk1;
+ }
+
+#if 0
+ /*
+ * Speed-optimized version for PC-2 + bitslicing.
+ * (Unused. Kept for reference only.)
+ */
+ sk0 = kl & (uint32_t)0x00100000;
+ sk0 |= (kl & (uint32_t)0x08008000) << 2;
+ sk0 |= (kl & (uint32_t)0x00400000) << 4;
+ sk0 |= (kl & (uint32_t)0x00800000) << 5;
+ sk0 |= (kl & (uint32_t)0x00040000) << 6;
+ sk0 |= (kl & (uint32_t)0x00010000) << 7;
+ sk0 |= (kl & (uint32_t)0x00000100) << 10;
+ sk0 |= (kl & (uint32_t)0x00022000) << 14;
+ sk0 |= (kl & (uint32_t)0x00000082) << 18;
+ sk0 |= (kl & (uint32_t)0x00000004) << 19;
+ sk0 |= (kl & (uint32_t)0x04000000) >> 10;
+ sk0 |= (kl & (uint32_t)0x00000010) << 26;
+ sk0 |= (kl & (uint32_t)0x01000000) >> 2;
+
+ sk0 |= kr & (uint32_t)0x00000100;
+ sk0 |= (kr & (uint32_t)0x00000008) << 1;
+ sk0 |= (kr & (uint32_t)0x00000200) << 4;
+ sk0 |= rotl(kr & (uint32_t)0x08000021, 6);
+ sk0 |= (kr & (uint32_t)0x01000000) >> 24;
+ sk0 |= (kr & (uint32_t)0x00000002) << 11;
+ sk0 |= (kr & (uint32_t)0x00100000) >> 18;
+ sk0 |= (kr & (uint32_t)0x00400000) >> 17;
+ sk0 |= (kr & (uint32_t)0x00800000) >> 14;
+ sk0 |= (kr & (uint32_t)0x02020000) >> 10;
+ sk0 |= (kr & (uint32_t)0x00080000) >> 5;
+ sk0 |= (kr & (uint32_t)0x00000040) >> 3;
+ sk0 |= (kr & (uint32_t)0x00000800) >> 1;
+
+ sk1 = kl & (uint32_t)0x02000000;
+ sk1 |= (kl & (uint32_t)0x00001000) << 5;
+ sk1 |= (kl & (uint32_t)0x00000200) << 11;
+ sk1 |= (kl & (uint32_t)0x00004000) << 15;
+ sk1 |= (kl & (uint32_t)0x00000020) << 16;
+ sk1 |= (kl & (uint32_t)0x00000800) << 17;
+ sk1 |= (kl & (uint32_t)0x00000001) << 24;
+ sk1 |= (kl & (uint32_t)0x00200000) >> 5;
+
+ sk1 |= (kr & (uint32_t)0x00000010) << 8;
+ sk1 |= (kr & (uint32_t)0x04000000) >> 17;
+ sk1 |= (kr & (uint32_t)0x00004000) >> 14;
+ sk1 |= (kr & (uint32_t)0x00000400) >> 9;
+ sk1 |= (kr & (uint32_t)0x00010000) >> 8;
+ sk1 |= (kr & (uint32_t)0x00001000) >> 7;
+ sk1 |= (kr & (uint32_t)0x00000080) >> 3;
+ sk1 |= (kr & (uint32_t)0x00008000) >> 2;
+#endif
+}
+
+/* see inner.h */
+unsigned
+br_des_ct_keysched(uint32_t *skey, const void *key, size_t key_len)
+{
+ switch (key_len) {
+ case 8:
+ keysched_unit(skey, key);
+ return 1;
+ case 16:
+ keysched_unit(skey, key);
+ keysched_unit(skey + 32, (const unsigned char *)key + 8);
+ br_des_rev_skey(skey + 32);
+ memcpy(skey + 64, skey, 32 * sizeof *skey);
+ return 3;
+ default:
+ keysched_unit(skey, key);
+ keysched_unit(skey + 32, (const unsigned char *)key + 8);
+ br_des_rev_skey(skey + 32);
+ keysched_unit(skey + 64, (const unsigned char *)key + 16);
+ return 3;
+ }
+}
+
+/*
+ * DES confusion function. This function performs expansion E (32 to
+ * 48 bits), XOR with subkey, S-boxes, and permutation P.
+ */
+static inline uint32_t
+Fconf(uint32_t r0, const uint32_t *sk)
+{
+ /*
+ * Each 6->4 S-box is virtually turned into four 6->1 boxes; we
+ * thus end up with 32 boxes that we call "T-boxes" here. We will
+ * evaluate them with bitslice code.
+ *
+ * Each T-box is a circuit of multiplexers (sort of) and thus
+ * takes 70 inputs: the 6 actual T-box inputs, and 64 constants
+ * that describe the T-box output for all combinations of the
+ * 6 inputs. With this model, all T-boxes are identical (with
+ * distinct inputs) and thus can be executed in parallel with
+ * bitslice code.
+ *
+ * T-boxes are numbered from 0 to 31, in least-to-most
+ * significant order. Thus, S-box S1 corresponds to T-boxes 31,
+ * 30, 29 and 28, in that order. T-box 'n' is computed with the
+ * bits at rank 'n' in the 32-bit words.
+ *
+ * Words x0 to x5 contain the T-box inputs 0 to 5.
+ */
+ uint32_t x0, x1, x2, x3, x4, x5, z0;
+ uint32_t y0, y1, y2, y3, y4, y5, y6, y7, y8, y9;
+ uint32_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19;
+ uint32_t y20, y21, y22, y23, y24, y25, y26, y27, y28, y29;
+ uint32_t y30;
+
+ /*
+ * Spread input bits over the 6 input words x*.
+ */
+ x1 = r0 & (uint32_t)0x11111111;
+ x2 = (r0 >> 1) & (uint32_t)0x11111111;
+ x3 = (r0 >> 2) & (uint32_t)0x11111111;
+ x4 = (r0 >> 3) & (uint32_t)0x11111111;
+ x1 = (x1 << 4) - x1;
+ x2 = (x2 << 4) - x2;
+ x3 = (x3 << 4) - x3;
+ x4 = (x4 << 4) - x4;
+ x0 = (x4 << 4) | (x4 >> 28);
+ x5 = (x1 >> 4) | (x1 << 28);
+
+ /*
+ * XOR with the subkey for this round.
+ */
+ x0 ^= sk[0];
+ x1 ^= sk[1];
+ x2 ^= sk[2];
+ x3 ^= sk[3];
+ x4 ^= sk[4];
+ x5 ^= sk[5];
+
+ /*
+ * The T-boxes are done in parallel, since they all use a
+ * "tree of multiplexer". We use "fake multiplexers":
+ *
+ * y = a ^ (x & b)
+ *
+ * computes y as either 'a' (if x == 0) or 'a ^ b' (if x == 1).
+ */
+ y0 = (uint32_t)0xEFA72C4D ^ (x0 & (uint32_t)0xEC7AC69C);
+ y1 = (uint32_t)0xAEAAEDFF ^ (x0 & (uint32_t)0x500FB821);
+ y2 = (uint32_t)0x37396665 ^ (x0 & (uint32_t)0x40EFA809);
+ y3 = (uint32_t)0x68D7B833 ^ (x0 & (uint32_t)0xA5EC0B28);
+ y4 = (uint32_t)0xC9C755BB ^ (x0 & (uint32_t)0x252CF820);
+ y5 = (uint32_t)0x73FC3606 ^ (x0 & (uint32_t)0x40205801);
+ y6 = (uint32_t)0xA2A0A918 ^ (x0 & (uint32_t)0xE220F929);
+ y7 = (uint32_t)0x8222BD90 ^ (x0 & (uint32_t)0x44A3F9E1);
+ y8 = (uint32_t)0xD6B6AC77 ^ (x0 & (uint32_t)0x794F104A);
+ y9 = (uint32_t)0x3069300C ^ (x0 & (uint32_t)0x026F320B);
+ y10 = (uint32_t)0x6CE0D5CC ^ (x0 & (uint32_t)0x7640B01A);
+ y11 = (uint32_t)0x59A9A22D ^ (x0 & (uint32_t)0x238F1572);
+ y12 = (uint32_t)0xAC6D0BD4 ^ (x0 & (uint32_t)0x7A63C083);
+ y13 = (uint32_t)0x21C83200 ^ (x0 & (uint32_t)0x11CCA000);
+ y14 = (uint32_t)0xA0E62188 ^ (x0 & (uint32_t)0x202F69AA);
+ /* y15 = (uint32_t)0x00000000 ^ (x0 & (uint32_t)0x00000000); */
+ y16 = (uint32_t)0xAF7D655A ^ (x0 & (uint32_t)0x51B33BE9);
+ y17 = (uint32_t)0xF0168AA3 ^ (x0 & (uint32_t)0x3B0FE8AE);
+ y18 = (uint32_t)0x90AA30C6 ^ (x0 & (uint32_t)0x90BF8816);
+ y19 = (uint32_t)0x5AB2750A ^ (x0 & (uint32_t)0x09E34F9B);
+ y20 = (uint32_t)0x5391BE65 ^ (x0 & (uint32_t)0x0103BE88);
+ y21 = (uint32_t)0x93372BAF ^ (x0 & (uint32_t)0x49AC8E25);
+ y22 = (uint32_t)0xF288210C ^ (x0 & (uint32_t)0x922C313D);
+ y23 = (uint32_t)0x920AF5C0 ^ (x0 & (uint32_t)0x70EF31B0);
+ y24 = (uint32_t)0x63D312C0 ^ (x0 & (uint32_t)0x6A707100);
+ y25 = (uint32_t)0x537B3006 ^ (x0 & (uint32_t)0xB97C9011);
+ y26 = (uint32_t)0xA2EFB0A5 ^ (x0 & (uint32_t)0xA320C959);
+ y27 = (uint32_t)0xBC8F96A5 ^ (x0 & (uint32_t)0x6EA0AB4A);
+ y28 = (uint32_t)0xFAD176A5 ^ (x0 & (uint32_t)0x6953DDF8);
+ y29 = (uint32_t)0x665A14A3 ^ (x0 & (uint32_t)0xF74F3E2B);
+ y30 = (uint32_t)0xF2EFF0CC ^ (x0 & (uint32_t)0xF0306CAD);
+ /* y31 = (uint32_t)0x00000000 ^ (x0 & (uint32_t)0x00000000); */
+
+ y0 = y0 ^ (x1 & y1);
+ y1 = y2 ^ (x1 & y3);
+ y2 = y4 ^ (x1 & y5);
+ y3 = y6 ^ (x1 & y7);
+ y4 = y8 ^ (x1 & y9);
+ y5 = y10 ^ (x1 & y11);
+ y6 = y12 ^ (x1 & y13);
+ y7 = y14; /* was: y14 ^ (x1 & y15) */
+ y8 = y16 ^ (x1 & y17);
+ y9 = y18 ^ (x1 & y19);
+ y10 = y20 ^ (x1 & y21);
+ y11 = y22 ^ (x1 & y23);
+ y12 = y24 ^ (x1 & y25);
+ y13 = y26 ^ (x1 & y27);
+ y14 = y28 ^ (x1 & y29);
+ y15 = y30; /* was: y30 ^ (x1 & y31) */
+
+ y0 = y0 ^ (x2 & y1);
+ y1 = y2 ^ (x2 & y3);
+ y2 = y4 ^ (x2 & y5);
+ y3 = y6 ^ (x2 & y7);
+ y4 = y8 ^ (x2 & y9);
+ y5 = y10 ^ (x2 & y11);
+ y6 = y12 ^ (x2 & y13);
+ y7 = y14 ^ (x2 & y15);
+
+ y0 = y0 ^ (x3 & y1);
+ y1 = y2 ^ (x3 & y3);
+ y2 = y4 ^ (x3 & y5);
+ y3 = y6 ^ (x3 & y7);
+
+ y0 = y0 ^ (x4 & y1);
+ y1 = y2 ^ (x4 & y3);
+
+ y0 = y0 ^ (x5 & y1);
+
+ /*
+ * The P permutation:
+ * -- Each bit move is converted into a mask + left rotation.
+ * -- Rotations that use the same movement are coalesced together.
+ * -- Left and right shifts are used as alternatives to a rotation
+ * where appropriate (this will help architectures that do not have
+ * a rotation opcode).
+ */
+ z0 = (y0 & (uint32_t)0x00000004) << 3;
+ z0 |= (y0 & (uint32_t)0x00004000) << 4;
+ z0 |= rotl(y0 & 0x12020120, 5);
+ z0 |= (y0 & (uint32_t)0x00100000) << 6;
+ z0 |= (y0 & (uint32_t)0x00008000) << 9;
+ z0 |= (y0 & (uint32_t)0x04000000) >> 22;
+ z0 |= (y0 & (uint32_t)0x00000001) << 11;
+ z0 |= rotl(y0 & 0x20000200, 12);
+ z0 |= (y0 & (uint32_t)0x00200000) >> 19;
+ z0 |= (y0 & (uint32_t)0x00000040) << 14;
+ z0 |= (y0 & (uint32_t)0x00010000) << 15;
+ z0 |= (y0 & (uint32_t)0x00000002) << 16;
+ z0 |= rotl(y0 & 0x40801800, 17);
+ z0 |= (y0 & (uint32_t)0x00080000) >> 13;
+ z0 |= (y0 & (uint32_t)0x00000010) << 21;
+ z0 |= (y0 & (uint32_t)0x01000000) >> 10;
+ z0 |= rotl(y0 & 0x88000008, 24);
+ z0 |= (y0 & (uint32_t)0x00000480) >> 7;
+ z0 |= (y0 & (uint32_t)0x00442000) >> 6;
+ return z0;
+}
+
+/*
+ * Process one block through 16 successive rounds, omitting the swap
+ * in the final round.
+ */
+static void
+process_block_unit(uint32_t *pl, uint32_t *pr, const uint32_t *sk_exp)
+{
+ int i;
+ uint32_t l, r;
+
+ l = *pl;
+ r = *pr;
+ for (i = 0; i < 16; i ++) {
+ uint32_t t;
+
+ t = l ^ Fconf(r, sk_exp);
+ l = r;
+ r = t;
+ sk_exp += 6;
+ }
+ *pl = r;
+ *pr = l;
+}
+
+/* see inner.h */
+void
+br_des_ct_process_block(unsigned num_rounds,
+ const uint32_t *sk_exp, void *block)
+{
+ unsigned char *buf;
+ uint32_t l, r;
+
+ buf = block;
+ l = br_dec32be(buf);
+ r = br_dec32be(buf + 4);
+ br_des_do_IP(&l, &r);
+ while (num_rounds -- > 0) {
+ process_block_unit(&l, &r, sk_exp);
+ sk_exp += 96;
+ }
+ br_des_do_invIP(&l, &r);
+ br_enc32be(buf, l);
+ br_enc32be(buf + 4, r);
+}
+
+/* see inner.h */
+void
+br_des_ct_skey_expand(uint32_t *sk_exp,
+ unsigned num_rounds, const uint32_t *skey)
+{
+ num_rounds <<= 4;
+ while (num_rounds -- > 0) {
+ uint32_t v, w0, w1, w2, w3;
+
+ v = *skey ++;
+ w0 = v & 0x11111111;
+ w1 = (v >> 1) & 0x11111111;
+ w2 = (v >> 2) & 0x11111111;
+ w3 = (v >> 3) & 0x11111111;
+ *sk_exp ++ = (w0 << 4) - w0;
+ *sk_exp ++ = (w1 << 4) - w1;
+ *sk_exp ++ = (w2 << 4) - w2;
+ *sk_exp ++ = (w3 << 4) - w3;
+ v = *skey ++;
+ w0 = v & 0x11111111;
+ w1 = (v >> 1) & 0x11111111;
+ *sk_exp ++ = (w0 << 4) - w0;
+ *sk_exp ++ = (w1 << 4) - w1;
+ }
+}
--- /dev/null
+/*
+ * 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_block.h */
+void
+br_des_ct_cbcdec_init(br_des_ct_cbcdec_keys *ctx,
+ const void *key, size_t len)
+{
+ ctx->vtable = &br_des_ct_cbcdec_vtable;
+ ctx->num_rounds = br_des_ct_keysched(ctx->skey, key, len);
+ if (len == 8) {
+ br_des_rev_skey(ctx->skey);
+ } else {
+ int i;
+
+ for (i = 0; i < 48; i += 2) {
+ uint32_t t;
+
+ t = ctx->skey[i];
+ ctx->skey[i] = ctx->skey[94 - i];
+ ctx->skey[94 - i] = t;
+ t = ctx->skey[i + 1];
+ ctx->skey[i + 1] = ctx->skey[95 - i];
+ ctx->skey[95 - i] = t;
+ }
+ }
+}
+
+/* see bearssl_block.h */
+void
+br_des_ct_cbcdec_run(const br_des_ct_cbcdec_keys *ctx,
+ void *iv, void *data, size_t len)
+{
+ unsigned char *buf, *ivbuf;
+ uint32_t sk_exp[288];
+
+ br_des_ct_skey_expand(sk_exp, ctx->num_rounds, ctx->skey);
+ ivbuf = iv;
+ buf = data;
+ while (len > 0) {
+ unsigned char tmp[8];
+ int i;
+
+ memcpy(tmp, buf, 8);
+ br_des_ct_process_block(ctx->num_rounds, sk_exp, buf);
+ for (i = 0; i < 8; i ++) {
+ buf[i] ^= ivbuf[i];
+ }
+ memcpy(ivbuf, tmp, 8);
+ buf += 8;
+ len -= 8;
+ }
+}
+
+/* see bearssl_block.h */
+const br_block_cbcdec_class br_des_ct_cbcdec_vtable = {
+ sizeof(br_des_ct_cbcdec_keys),
+ 8,
+ 3,
+ (void (*)(const br_block_cbcdec_class **, const void *, size_t))
+ &br_des_ct_cbcdec_init,
+ (void (*)(const br_block_cbcdec_class *const *, void *, void *, size_t))
+ &br_des_ct_cbcdec_run
+};
--- /dev/null
+/*
+ * 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_block.h */
+void
+br_des_ct_cbcenc_init(br_des_ct_cbcenc_keys *ctx,
+ const void *key, size_t len)
+{
+ ctx->vtable = &br_des_ct_cbcenc_vtable;
+ ctx->num_rounds = br_des_ct_keysched(ctx->skey, key, len);
+}
+
+/* see bearssl_block.h */
+void
+br_des_ct_cbcenc_run(const br_des_ct_cbcenc_keys *ctx,
+ void *iv, void *data, size_t len)
+{
+ unsigned char *buf, *ivbuf;
+ uint32_t sk_exp[288];
+
+ br_des_ct_skey_expand(sk_exp, ctx->num_rounds, ctx->skey);
+ ivbuf = iv;
+ buf = data;
+ while (len > 0) {
+ int i;
+
+ for (i = 0; i < 8; i ++) {
+ buf[i] ^= ivbuf[i];
+ }
+ br_des_ct_process_block(ctx->num_rounds, sk_exp, buf);
+ memcpy(ivbuf, buf, 8);
+ buf += 8;
+ len -= 8;
+ }
+}
+
+/* see bearssl_block.h */
+const br_block_cbcenc_class br_des_ct_cbcenc_vtable = {
+ sizeof(br_des_ct_cbcenc_keys),
+ 8,
+ 3,
+ (void (*)(const br_block_cbcenc_class **, const void *, size_t))
+ &br_des_ct_cbcenc_init,
+ (void (*)(const br_block_cbcenc_class *const *, void *, void *, size_t))
+ &br_des_ct_cbcenc_run
+};
--- /dev/null
+/*
+ * 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 inner.h */
+void
+br_des_do_IP(uint32_t *xl, uint32_t *xr)
+{
+ /*
+ * Permutation algorithm is initially from Richard Outerbridge;
+ * implementation here is adapted from Crypto++ "des.cpp" file
+ * (which is in public domain).
+ */
+ uint32_t l, r, t;
+
+ l = *xl;
+ r = *xr;
+ t = ((l >> 4) ^ r) & (uint32_t)0x0F0F0F0F;
+ r ^= t;
+ l ^= t << 4;
+ t = ((l >> 16) ^ r) & (uint32_t)0x0000FFFF;
+ r ^= t;
+ l ^= t << 16;
+ t = ((r >> 2) ^ l) & (uint32_t)0x33333333;
+ l ^= t;
+ r ^= t << 2;
+ t = ((r >> 8) ^ l) & (uint32_t)0x00FF00FF;
+ l ^= t;
+ r ^= t << 8;
+ t = ((l >> 1) ^ r) & (uint32_t)0x55555555;
+ r ^= t;
+ l ^= t << 1;
+ *xl = l;
+ *xr = r;
+}
+
+/* see inner.h */
+void
+br_des_do_invIP(uint32_t *xl, uint32_t *xr)
+{
+ /*
+ * See br_des_do_IP().
+ */
+ uint32_t l, r, t;
+
+ l = *xl;
+ r = *xr;
+ t = ((l >> 1) ^ r) & 0x55555555;
+ r ^= t;
+ l ^= t << 1;
+ t = ((r >> 8) ^ l) & 0x00FF00FF;
+ l ^= t;
+ r ^= t << 8;
+ t = ((r >> 2) ^ l) & 0x33333333;
+ l ^= t;
+ r ^= t << 2;
+ t = ((l >> 16) ^ r) & 0x0000FFFF;
+ r ^= t;
+ l ^= t << 16;
+ t = ((l >> 4) ^ r) & 0x0F0F0F0F;
+ r ^= t;
+ l ^= t << 4;
+ *xl = l;
+ *xr = r;
+}
+
+/* see inner.h */
+void
+br_des_keysched_unit(uint32_t *skey, const void *key)
+{
+ uint32_t xl, xr, kl, kr;
+ int i;
+
+ xl = br_dec32be(key);
+ xr = br_dec32be((const unsigned char *)key + 4);
+
+ /*
+ * Permutation PC-1 is quite similar to the IP permutation.
+ * Definition of IP (in FIPS 46-3 notations) is:
+ * 58 50 42 34 26 18 10 2
+ * 60 52 44 36 28 20 12 4
+ * 62 54 46 38 30 22 14 6
+ * 64 56 48 40 32 24 16 8
+ * 57 49 41 33 25 17 9 1
+ * 59 51 43 35 27 19 11 3
+ * 61 53 45 37 29 21 13 5
+ * 63 55 47 39 31 23 15 7
+ *
+ * Definition of PC-1 is:
+ * 57 49 41 33 25 17 9 1
+ * 58 50 42 34 26 18 10 2
+ * 59 51 43 35 27 19 11 3
+ * 60 52 44 36
+ * 63 55 47 39 31 23 15 7
+ * 62 54 46 38 30 22 14 6
+ * 61 53 45 37 29 21 13 5
+ * 28 20 12 4
+ */
+ br_des_do_IP(&xl, &xr);
+ kl = ((xr & (uint32_t)0xFF000000) >> 4)
+ | ((xl & (uint32_t)0xFF000000) >> 12)
+ | ((xr & (uint32_t)0x00FF0000) >> 12)
+ | ((xl & (uint32_t)0x00FF0000) >> 20);
+ kr = ((xr & (uint32_t)0x000000FF) << 20)
+ | ((xl & (uint32_t)0x0000FF00) << 4)
+ | ((xr & (uint32_t)0x0000FF00) >> 4)
+ | ((xl & (uint32_t)0x000F0000) >> 16);
+
+ /*
+ * For each round, rotate the two 28-bit words kl and kr.
+ * The extraction of the 48-bit subkey (PC-2) is not done yet.
+ */
+ for (i = 0; i < 16; i ++) {
+ if ((1 << i) & 0x8103) {
+ kl = (kl << 1) | (kl >> 27);
+ kr = (kr << 1) | (kr >> 27);
+ } else {
+ kl = (kl << 2) | (kl >> 26);
+ kr = (kr << 2) | (kr >> 26);
+ }
+ kl &= (uint32_t)0x0FFFFFFF;
+ kr &= (uint32_t)0x0FFFFFFF;
+ skey[(i << 1) + 0] = kl;
+ skey[(i << 1) + 1] = kr;
+ }
+}
+
+/* see inner.h */
+void
+br_des_rev_skey(uint32_t *skey)
+{
+ int i;
+
+ for (i = 0; i < 16; i += 2) {
+ uint32_t t;
+
+ t = skey[i + 0];
+ skey[i + 0] = skey[30 - i];
+ skey[30 - i] = t;
+ t = skey[i + 1];
+ skey[i + 1] = skey[31 - i];
+ skey[31 - i] = t;
+ }
+}
--- /dev/null
+/*
+ * 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"
+
+/*
+ * PC2left[x] tells where bit x goes when applying PC-2. 'x' is a bit
+ * position in the left rotated key word. Both position are in normal
+ * order (rightmost bit is 0).
+ */
+static const unsigned char PC2left[] = {
+ 16, 3, 7, 24, 20, 11, 24,
+ 13, 2, 10, 24, 22, 5, 15,
+ 23, 1, 9, 21, 12, 24, 6,
+ 4, 14, 18, 8, 17, 0, 19
+};
+
+/*
+ * Similar to PC2left[x], for the right rotated key word.
+ */
+static const unsigned char PC2right[] = {
+ 8, 18, 24, 6, 22, 15, 3,
+ 10, 12, 19, 5, 14, 11, 24,
+ 4, 23, 16, 9, 24, 20, 2,
+ 24, 7, 13, 0, 21, 17, 1
+};
+
+/*
+ * S-boxes and PC-1 merged.
+ */
+static const uint32_t S1[] = {
+ 0x00808200, 0x00000000, 0x00008000, 0x00808202,
+ 0x00808002, 0x00008202, 0x00000002, 0x00008000,
+ 0x00000200, 0x00808200, 0x00808202, 0x00000200,
+ 0x00800202, 0x00808002, 0x00800000, 0x00000002,
+ 0x00000202, 0x00800200, 0x00800200, 0x00008200,
+ 0x00008200, 0x00808000, 0x00808000, 0x00800202,
+ 0x00008002, 0x00800002, 0x00800002, 0x00008002,
+ 0x00000000, 0x00000202, 0x00008202, 0x00800000,
+ 0x00008000, 0x00808202, 0x00000002, 0x00808000,
+ 0x00808200, 0x00800000, 0x00800000, 0x00000200,
+ 0x00808002, 0x00008000, 0x00008200, 0x00800002,
+ 0x00000200, 0x00000002, 0x00800202, 0x00008202,
+ 0x00808202, 0x00008002, 0x00808000, 0x00800202,
+ 0x00800002, 0x00000202, 0x00008202, 0x00808200,
+ 0x00000202, 0x00800200, 0x00800200, 0x00000000,
+ 0x00008002, 0x00008200, 0x00000000, 0x00808002
+};
+
+static const uint32_t S2[] = {
+ 0x40084010, 0x40004000, 0x00004000, 0x00084010,
+ 0x00080000, 0x00000010, 0x40080010, 0x40004010,
+ 0x40000010, 0x40084010, 0x40084000, 0x40000000,
+ 0x40004000, 0x00080000, 0x00000010, 0x40080010,
+ 0x00084000, 0x00080010, 0x40004010, 0x00000000,
+ 0x40000000, 0x00004000, 0x00084010, 0x40080000,
+ 0x00080010, 0x40000010, 0x00000000, 0x00084000,
+ 0x00004010, 0x40084000, 0x40080000, 0x00004010,
+ 0x00000000, 0x00084010, 0x40080010, 0x00080000,
+ 0x40004010, 0x40080000, 0x40084000, 0x00004000,
+ 0x40080000, 0x40004000, 0x00000010, 0x40084010,
+ 0x00084010, 0x00000010, 0x00004000, 0x40000000,
+ 0x00004010, 0x40084000, 0x00080000, 0x40000010,
+ 0x00080010, 0x40004010, 0x40000010, 0x00080010,
+ 0x00084000, 0x00000000, 0x40004000, 0x00004010,
+ 0x40000000, 0x40080010, 0x40084010, 0x00084000
+};
+
+static const uint32_t S3[] = {
+ 0x00000104, 0x04010100, 0x00000000, 0x04010004,
+ 0x04000100, 0x00000000, 0x00010104, 0x04000100,
+ 0x00010004, 0x04000004, 0x04000004, 0x00010000,
+ 0x04010104, 0x00010004, 0x04010000, 0x00000104,
+ 0x04000000, 0x00000004, 0x04010100, 0x00000100,
+ 0x00010100, 0x04010000, 0x04010004, 0x00010104,
+ 0x04000104, 0x00010100, 0x00010000, 0x04000104,
+ 0x00000004, 0x04010104, 0x00000100, 0x04000000,
+ 0x04010100, 0x04000000, 0x00010004, 0x00000104,
+ 0x00010000, 0x04010100, 0x04000100, 0x00000000,
+ 0x00000100, 0x00010004, 0x04010104, 0x04000100,
+ 0x04000004, 0x00000100, 0x00000000, 0x04010004,
+ 0x04000104, 0x00010000, 0x04000000, 0x04010104,
+ 0x00000004, 0x00010104, 0x00010100, 0x04000004,
+ 0x04010000, 0x04000104, 0x00000104, 0x04010000,
+ 0x00010104, 0x00000004, 0x04010004, 0x00010100
+};
+
+static const uint32_t S4[] = {
+ 0x80401000, 0x80001040, 0x80001040, 0x00000040,
+ 0x00401040, 0x80400040, 0x80400000, 0x80001000,
+ 0x00000000, 0x00401000, 0x00401000, 0x80401040,
+ 0x80000040, 0x00000000, 0x00400040, 0x80400000,
+ 0x80000000, 0x00001000, 0x00400000, 0x80401000,
+ 0x00000040, 0x00400000, 0x80001000, 0x00001040,
+ 0x80400040, 0x80000000, 0x00001040, 0x00400040,
+ 0x00001000, 0x00401040, 0x80401040, 0x80000040,
+ 0x00400040, 0x80400000, 0x00401000, 0x80401040,
+ 0x80000040, 0x00000000, 0x00000000, 0x00401000,
+ 0x00001040, 0x00400040, 0x80400040, 0x80000000,
+ 0x80401000, 0x80001040, 0x80001040, 0x00000040,
+ 0x80401040, 0x80000040, 0x80000000, 0x00001000,
+ 0x80400000, 0x80001000, 0x00401040, 0x80400040,
+ 0x80001000, 0x00001040, 0x00400000, 0x80401000,
+ 0x00000040, 0x00400000, 0x00001000, 0x00401040
+};
+
+static const uint32_t S5[] = {
+ 0x00000080, 0x01040080, 0x01040000, 0x21000080,
+ 0x00040000, 0x00000080, 0x20000000, 0x01040000,
+ 0x20040080, 0x00040000, 0x01000080, 0x20040080,
+ 0x21000080, 0x21040000, 0x00040080, 0x20000000,
+ 0x01000000, 0x20040000, 0x20040000, 0x00000000,
+ 0x20000080, 0x21040080, 0x21040080, 0x01000080,
+ 0x21040000, 0x20000080, 0x00000000, 0x21000000,
+ 0x01040080, 0x01000000, 0x21000000, 0x00040080,
+ 0x00040000, 0x21000080, 0x00000080, 0x01000000,
+ 0x20000000, 0x01040000, 0x21000080, 0x20040080,
+ 0x01000080, 0x20000000, 0x21040000, 0x01040080,
+ 0x20040080, 0x00000080, 0x01000000, 0x21040000,
+ 0x21040080, 0x00040080, 0x21000000, 0x21040080,
+ 0x01040000, 0x00000000, 0x20040000, 0x21000000,
+ 0x00040080, 0x01000080, 0x20000080, 0x00040000,
+ 0x00000000, 0x20040000, 0x01040080, 0x20000080
+};
+
+static const uint32_t S6[] = {
+ 0x10000008, 0x10200000, 0x00002000, 0x10202008,
+ 0x10200000, 0x00000008, 0x10202008, 0x00200000,
+ 0x10002000, 0x00202008, 0x00200000, 0x10000008,
+ 0x00200008, 0x10002000, 0x10000000, 0x00002008,
+ 0x00000000, 0x00200008, 0x10002008, 0x00002000,
+ 0x00202000, 0x10002008, 0x00000008, 0x10200008,
+ 0x10200008, 0x00000000, 0x00202008, 0x10202000,
+ 0x00002008, 0x00202000, 0x10202000, 0x10000000,
+ 0x10002000, 0x00000008, 0x10200008, 0x00202000,
+ 0x10202008, 0x00200000, 0x00002008, 0x10000008,
+ 0x00200000, 0x10002000, 0x10000000, 0x00002008,
+ 0x10000008, 0x10202008, 0x00202000, 0x10200000,
+ 0x00202008, 0x10202000, 0x00000000, 0x10200008,
+ 0x00000008, 0x00002000, 0x10200000, 0x00202008,
+ 0x00002000, 0x00200008, 0x10002008, 0x00000000,
+ 0x10202000, 0x10000000, 0x00200008, 0x10002008
+};
+
+static const uint32_t S7[] = {
+ 0x00100000, 0x02100001, 0x02000401, 0x00000000,
+ 0x00000400, 0x02000401, 0x00100401, 0x02100400,
+ 0x02100401, 0x00100000, 0x00000000, 0x02000001,
+ 0x00000001, 0x02000000, 0x02100001, 0x00000401,
+ 0x02000400, 0x00100401, 0x00100001, 0x02000400,
+ 0x02000001, 0x02100000, 0x02100400, 0x00100001,
+ 0x02100000, 0x00000400, 0x00000401, 0x02100401,
+ 0x00100400, 0x00000001, 0x02000000, 0x00100400,
+ 0x02000000, 0x00100400, 0x00100000, 0x02000401,
+ 0x02000401, 0x02100001, 0x02100001, 0x00000001,
+ 0x00100001, 0x02000000, 0x02000400, 0x00100000,
+ 0x02100400, 0x00000401, 0x00100401, 0x02100400,
+ 0x00000401, 0x02000001, 0x02100401, 0x02100000,
+ 0x00100400, 0x00000000, 0x00000001, 0x02100401,
+ 0x00000000, 0x00100401, 0x02100000, 0x00000400,
+ 0x02000001, 0x02000400, 0x00000400, 0x00100001
+};
+
+static const uint32_t S8[] = {
+ 0x08000820, 0x00000800, 0x00020000, 0x08020820,
+ 0x08000000, 0x08000820, 0x00000020, 0x08000000,
+ 0x00020020, 0x08020000, 0x08020820, 0x00020800,
+ 0x08020800, 0x00020820, 0x00000800, 0x00000020,
+ 0x08020000, 0x08000020, 0x08000800, 0x00000820,
+ 0x00020800, 0x00020020, 0x08020020, 0x08020800,
+ 0x00000820, 0x00000000, 0x00000000, 0x08020020,
+ 0x08000020, 0x08000800, 0x00020820, 0x00020000,
+ 0x00020820, 0x00020000, 0x08020800, 0x00000800,
+ 0x00000020, 0x08020020, 0x00000800, 0x00020820,
+ 0x08000800, 0x00000020, 0x08000020, 0x08020000,
+ 0x08020020, 0x08000000, 0x00020000, 0x08000820,
+ 0x00000000, 0x08020820, 0x00020020, 0x08000020,
+ 0x08020000, 0x08000800, 0x08000820, 0x00000000,
+ 0x08020820, 0x00020800, 0x00020800, 0x00000820,
+ 0x00000820, 0x00020020, 0x08000000, 0x08020800
+};
+
+static inline uint32_t
+Fconf(uint32_t r0, uint32_t skl, uint32_t skr)
+{
+ uint32_t r1;
+
+ r1 = (r0 << 16) | (r0 >> 16);
+ return
+ S1[((r1 >> 11) ^ (skl >> 18)) & 0x3F]
+ | S2[((r0 >> 23) ^ (skl >> 12)) & 0x3F]
+ | S3[((r0 >> 19) ^ (skl >> 6)) & 0x3F]
+ | S4[((r0 >> 15) ^ (skl )) & 0x3F]
+ | S5[((r0 >> 11) ^ (skr >> 18)) & 0x3F]
+ | S6[((r0 >> 7) ^ (skr >> 12)) & 0x3F]
+ | S7[((r0 >> 3) ^ (skr >> 6)) & 0x3F]
+ | S8[((r1 >> 15) ^ (skr )) & 0x3F];
+}
+
+static void
+process_block_unit(uint32_t *pl, uint32_t *pr, const uint32_t *skey)
+{
+ int i;
+ uint32_t l, r;
+
+ l = *pl;
+ r = *pr;
+ for (i = 0; i < 16; i ++) {
+ uint32_t t;
+
+ t = l ^ Fconf(r, skey[(i << 1) + 0], skey[(i << 1) + 1]);
+ l = r;
+ r = t;
+ }
+ *pl = r;
+ *pr = l;
+}
+
+/* see inner.h */
+void
+br_des_tab_process_block(unsigned num_rounds, const uint32_t *skey, void *block)
+{
+ unsigned char *buf;
+ uint32_t l, r;
+
+ buf = block;
+ l = br_dec32be(buf);
+ r = br_dec32be(buf + 4);
+ br_des_do_IP(&l, &r);
+ while (num_rounds -- > 0) {
+ process_block_unit(&l, &r, skey);
+ skey += 32;
+ }
+ br_des_do_invIP(&l, &r);
+ br_enc32be(buf, l);
+ br_enc32be(buf + 4, r);
+}
+
+static void
+keysched_unit(uint32_t *skey, const void *key)
+{
+ int i;
+
+ br_des_keysched_unit(skey, key);
+
+ /*
+ * Apply PC-2 to get the 48-bit subkeys.
+ */
+ for (i = 0; i < 16; i ++) {
+ uint32_t xl, xr, ul, ur;
+ int j;
+
+ xl = skey[(i << 1) + 0];
+ xr = skey[(i << 1) + 1];
+ ul = 0;
+ ur = 0;
+ for (j = 0; j < 28; j ++) {
+ ul |= (xl & 1) << PC2left[j];
+ ur |= (xr & 1) << PC2right[j];
+ xl >>= 1;
+ xr >>= 1;
+ }
+ skey[(i << 1) + 0] = ul;
+ skey[(i << 1) + 1] = ur;
+ }
+}
+
+/* see inner.h */
+unsigned
+br_des_tab_keysched(uint32_t *skey, const void *key, size_t key_len)
+{
+ switch (key_len) {
+ case 8:
+ keysched_unit(skey, key);
+ return 1;
+ case 16:
+ keysched_unit(skey, key);
+ keysched_unit(skey + 32, (const unsigned char *)key + 8);
+ br_des_rev_skey(skey + 32);
+ memcpy(skey + 64, skey, 32 * sizeof *skey);
+ return 3;
+ default:
+ keysched_unit(skey, key);
+ keysched_unit(skey + 32, (const unsigned char *)key + 8);
+ br_des_rev_skey(skey + 32);
+ keysched_unit(skey + 64, (const unsigned char *)key + 16);
+ return 3;
+ }
+}
--- /dev/null
+/*
+ * 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_block.h */
+void
+br_des_tab_cbcdec_init(br_des_tab_cbcdec_keys *ctx,
+ const void *key, size_t len)
+{
+ ctx->vtable = &br_des_tab_cbcdec_vtable;
+ ctx->num_rounds = br_des_tab_keysched(ctx->skey, key, len);
+ if (len == 8) {
+ br_des_rev_skey(ctx->skey);
+ } else {
+ int i;
+
+ for (i = 0; i < 48; i += 2) {
+ uint32_t t;
+
+ t = ctx->skey[i];
+ ctx->skey[i] = ctx->skey[94 - i];
+ ctx->skey[94 - i] = t;
+ t = ctx->skey[i + 1];
+ ctx->skey[i + 1] = ctx->skey[95 - i];
+ ctx->skey[95 - i] = t;
+ }
+ }
+}
+
+/* see bearssl_block.h */
+void
+br_des_tab_cbcdec_run(const br_des_tab_cbcdec_keys *ctx,
+ void *iv, void *data, size_t len)
+{
+ unsigned char *buf, *ivbuf;
+
+ ivbuf = iv;
+ buf = data;
+ while (len > 0) {
+ unsigned char tmp[8];
+ int i;
+
+ memcpy(tmp, buf, 8);
+ br_des_tab_process_block(ctx->num_rounds, ctx->skey, buf);
+ for (i = 0; i < 8; i ++) {
+ buf[i] ^= ivbuf[i];
+ }
+ memcpy(ivbuf, tmp, 8);
+ buf += 8;
+ len -= 8;
+ }
+}
+
+/* see bearssl_block.h */
+const br_block_cbcdec_class br_des_tab_cbcdec_vtable = {
+ sizeof(br_des_tab_cbcdec_keys),
+ 8,
+ 3,
+ (void (*)(const br_block_cbcdec_class **, const void *, size_t))
+ &br_des_tab_cbcdec_init,
+ (void (*)(const br_block_cbcdec_class *const *, void *, void *, size_t))
+ &br_des_tab_cbcdec_run
+};
--- /dev/null
+/*
+ * 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_block.h */
+void
+br_des_tab_cbcenc_init(br_des_tab_cbcenc_keys *ctx,
+ const void *key, size_t len)
+{
+ ctx->vtable = &br_des_tab_cbcenc_vtable;
+ ctx->num_rounds = br_des_tab_keysched(ctx->skey, key, len);
+}
+
+/* see bearssl_block.h */
+void
+br_des_tab_cbcenc_run(const br_des_tab_cbcenc_keys *ctx,
+ void *iv, void *data, size_t len)
+{
+ unsigned char *buf, *ivbuf;
+
+ ivbuf = iv;
+ buf = data;
+ while (len > 0) {
+ int i;
+
+ for (i = 0; i < 8; i ++) {
+ buf[i] ^= ivbuf[i];
+ }
+ br_des_tab_process_block(ctx->num_rounds, ctx->skey, buf);
+ memcpy(ivbuf, buf, 8);
+ buf += 8;
+ len -= 8;
+ }
+}
+
+/* see bearssl_block.h */
+const br_block_cbcenc_class br_des_tab_cbcenc_vtable = {
+ sizeof(br_des_tab_cbcenc_keys),
+ 8,
+ 3,
+ (void (*)(const br_block_cbcenc_class **, const void *, size_t))
+ &br_des_tab_cbcenc_init,
+ (void (*)(const br_block_cbcenc_class *const *, void *, void *, size_t))
+ &br_des_tab_cbcenc_run
+};
--- /dev/null
+\ 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 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 *)((unsigned char *)CTX + addr) = T0_POP();
+}
+
+cc: set32 ( val addr -- ) {
+ uint32_t addr = T0_POP();
+ *(uint32_t *)((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 *)((unsigned char *)CTX + addr));
+}
+
+cc: get32 ( addr -- val ) {
+ uint32_t addr = T0_POP();
+ T0_PUSH(*(uint32_t *)((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 certicate 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 0xFFFFFF > 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
+
+\ 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 iself 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 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");
+}
--- /dev/null
+/* 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 uint8_t 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 *)((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 uint8_t 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 uint8_t 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, 0x87,
+ 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)
+
+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() break
+
+ dp = ((t0_context *)t0ctx)->dp;
+ rp = ((t0_context *)t0ctx)->rp;
+ ip = ((t0_context *)t0ctx)->ip;
+ for (;;) {
+ uint32_t t0x;
+
+ t0x = t0_parse7E_unsigned(&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;
+}
--- /dev/null
+\ 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 *)((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
+ ;
--- /dev/null
+/* 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 uint8_t 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 *)((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 uint8_t 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 uint8_t 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, 0x87, 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)
+
+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() break
+
+ dp = ((t0_context *)t0ctx)->dp;
+ rp = ((t0_context *)t0ctx)->rp;
+ ip = ((t0_context *)t0ctx)->ip;
+ for (;;) {
+ uint32_t t0x;
+
+ t0x = t0_parse7E_unsigned(&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 *)((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;
+}
--- /dev/null
+\ 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 *)((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
+ ;
--- /dev/null
+/*
+ * 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)
+{
+ ctx->vtable = &br_x509_knownkey_vtable;
+ ctx->pkey.key_type = BR_KEYTYPE_RSA;
+ ctx->pkey.key.rsa = *pk;
+}
+
+/* see bearssl_x509.h */
+void
+br_x509_knownkey_init_ec(br_x509_knownkey_context *ctx,
+ const br_ec_public_key *pk)
+{
+ ctx->vtable = &br_x509_knownkey_vtable;
+ ctx->pkey.key_type = BR_KEYTYPE_EC;
+ ctx->pkey.key.ec = *pk;
+}
+
+static void
+kk_start_chain(const br_x509_class **ctx,
+ unsigned expected_key_type, const char *server_name)
+{
+ (void)ctx;
+ (void)expected_key_type;
+ (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)
+{
+ return &((const br_x509_knownkey_context *)ctx)->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
+};
--- /dev/null
+/* 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 uint8_t 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.
+ */
+
+#ifndef BR_USE_UNIX_TIME
+#if defined __unix__ || defined __linux__ \
+ || defined _POSIX_SOURCE || defined _POSIX_C_SOURCE \
+ || (defined __APPLE__ && defined __MACH__)
+#define BR_USE_UNIX_TIME 1
+#endif
+#endif
+
+#ifndef BR_USE_WIN32_TIME
+#if defined _WIN32 || defined _WIN64
+#define BR_USE_WIN32_TIME 1
+#endif
+#endif
+
+#if BR_USE_UNIX_TIME
+#include <time.h>
+#endif
+
+#if BR_USE_WIN32_TIME
+#include <windows.h>
+#endif
+
+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,
+ unsigned expected_key_type, const char *server_name)
+{
+ br_x509_minimal_context *cc;
+
+ cc = (br_x509_minimal_context *)ctx;
+ 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);
+ cc->expected_key_type = expected_key_type;
+ 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 *)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 *)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 *)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 *)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)
+{
+ br_x509_minimal_context *cc;
+
+ cc = (br_x509_minimal_context *)ctx;
+ if (cc->err == BR_ERR_X509_OK
+ || cc->err == BR_ERR_X509_NOT_TRUSTED)
+ {
+ return &((br_x509_minimal_context *)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 *)((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;
+}
+
+/*
+ * 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;
+ }
+}
+
+/*
+ * 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 const uint8_t 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,
+ 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, 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 uint8_t t0_codeblock[] = {
+ 0x00, 0x01, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x11, 0x00, 0x00, 0x01,
+ 0x01, 0x09, 0x00, 0x00, 0x01, 0x01, 0x0A, 0x00, 0x00, 0x22, 0x22, 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_ERR_X509_WRONG_KEY_TYPE), 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, expected_key_type)), 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, 0x81, 0x31,
+ 0x6E, 0x00, 0x00, 0x01, 0x80, 0x73, 0x00, 0x00, 0x01, 0x80, 0x7C, 0x00,
+ 0x00, 0x01, 0x81, 0x02, 0x00, 0x00, 0x01, 0x82, 0x08, 0x00, 0x00, 0x01,
+ 0x81, 0x70, 0x00, 0x00, 0x01, 0x81, 0x64, 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, 0x23, 0x02, 0x01, 0x13, 0x39, 0x02,
+ 0x00, 0x0F, 0x15, 0x00, 0x00, 0x05, 0x02, 0x4F, 0x26, 0x00, 0x00, 0x06,
+ 0x02, 0x50, 0x26, 0x00, 0x00, 0x01, 0x10, 0x73, 0x00, 0x00, 0x11, 0x05,
+ 0x02, 0x53, 0x26, 0x70, 0x00, 0x00, 0x11, 0x05, 0x02, 0x53, 0x26, 0x71,
+ 0x00, 0x00, 0x06, 0x02, 0x49, 0x26, 0x00, 0x00, 0x01, 0x82, 0x00, 0x00,
+ 0x00, 0x23, 0x1E, 0x01, 0x08, 0x0E, 0x39, 0x3D, 0x1E, 0x09, 0x00, 0x09,
+ 0x03, 0x00, 0x59, 0x29, 0x81, 0x1D, 0x37, 0x81, 0x1D, 0x81, 0x20, 0x23,
+ 0x01, 0x20, 0x11, 0x06, 0x15, 0x22, 0x70, 0x81, 0x1B, 0x81, 0x20, 0x01,
+ 0x02, 0x74, 0x81, 0x1E, 0x01, 0x02, 0x12, 0x06, 0x02, 0x54, 0x26, 0x75,
+ 0x81, 0x20, 0x01, 0x02, 0x74, 0x81, 0x1C, 0x81, 0x1D, 0x81, 0x2A, 0x81,
+ 0x10, 0x63, 0x5F, 0x1F, 0x16, 0x81, 0x1D, 0x81, 0x15, 0x27, 0x67, 0x06,
+ 0x02, 0x48, 0x26, 0x81, 0x15, 0x27, 0x6E, 0x06, 0x02, 0x48, 0x26, 0x75,
+ 0x81, 0x10, 0x02, 0x00, 0x06, 0x05, 0x2B, 0x03, 0x01, 0x04, 0x08, 0x5F,
+ 0x66, 0x1F, 0x25, 0x05, 0x02, 0x47, 0x26, 0x66, 0x63, 0x1F, 0x16, 0x81,
+ 0x1D, 0x81, 0x1D, 0x81, 0x11, 0x05, 0x02, 0x54, 0x26, 0x81, 0x24, 0x24,
+ 0x06, 0x2C, 0x81, 0x2A, 0x81, 0x12, 0x81, 0x1D, 0x61, 0x81, 0x18, 0x03,
+ 0x03, 0x61, 0x39, 0x02, 0x03, 0x09, 0x39, 0x02, 0x03, 0x0A, 0x81, 0x18,
+ 0x03, 0x04, 0x75, 0x62, 0x28, 0x01, 0x81, 0x00, 0x09, 0x02, 0x03, 0x12,
+ 0x06, 0x02, 0x55, 0x26, 0x75, 0x58, 0x03, 0x02, 0x04, 0x3E, 0x81, 0x01,
+ 0x24, 0x06, 0x37, 0x81, 0x11, 0x05, 0x02, 0x54, 0x26, 0x68, 0x24, 0x06,
+ 0x04, 0x01, 0x17, 0x04, 0x12, 0x69, 0x24, 0x06, 0x04, 0x01, 0x18, 0x04,
+ 0x0A, 0x6A, 0x24, 0x06, 0x04, 0x01, 0x19, 0x04, 0x02, 0x54, 0x26, 0x03,
+ 0x05, 0x75, 0x81, 0x12, 0x23, 0x03, 0x06, 0x23, 0x61, 0x32, 0x0D, 0x06,
+ 0x02, 0x4D, 0x26, 0x81, 0x13, 0x57, 0x03, 0x02, 0x04, 0x02, 0x54, 0x26,
+ 0x75, 0x02, 0x00, 0x06, 0x33, 0x60, 0x2A, 0x01, 0x0F, 0x15, 0x23, 0x06,
+ 0x09, 0x02, 0x02, 0x11, 0x05, 0x02, 0x56, 0x26, 0x04, 0x01, 0x22, 0x02,
+ 0x02, 0x58, 0x2E, 0x11, 0x06, 0x08, 0x22, 0x02, 0x03, 0x02, 0x04, 0x1D,
+ 0x04, 0x10, 0x57, 0x2E, 0x11, 0x06, 0x08, 0x22, 0x02, 0x05, 0x02, 0x06,
+ 0x1C, 0x04, 0x03, 0x54, 0x26, 0x22, 0x04, 0x24, 0x02, 0x02, 0x58, 0x2E,
+ 0x11, 0x06, 0x08, 0x22, 0x02, 0x03, 0x02, 0x04, 0x21, 0x04, 0x10, 0x57,
+ 0x2E, 0x11, 0x06, 0x08, 0x22, 0x02, 0x05, 0x02, 0x06, 0x20, 0x04, 0x03,
+ 0x54, 0x26, 0x22, 0x23, 0x06, 0x01, 0x26, 0x22, 0x01, 0x00, 0x03, 0x07,
+ 0x81, 0x21, 0x01, 0x21, 0x81, 0x07, 0x01, 0x22, 0x81, 0x07, 0x23, 0x01,
+ 0x23, 0x11, 0x06, 0x81, 0x36, 0x22, 0x70, 0x81, 0x1B, 0x81, 0x1D, 0x23,
+ 0x06, 0x81, 0x28, 0x01, 0x00, 0x03, 0x08, 0x81, 0x1D, 0x81, 0x11, 0x22,
+ 0x81, 0x20, 0x23, 0x01, 0x01, 0x11, 0x06, 0x06, 0x81, 0x14, 0x03, 0x08,
+ 0x81, 0x20, 0x01, 0x04, 0x74, 0x81, 0x1B, 0x6D, 0x24, 0x06, 0x11, 0x02,
+ 0x00, 0x06, 0x04, 0x81, 0x2B, 0x04, 0x06, 0x81, 0x0E, 0x01, 0x7F, 0x03,
+ 0x07, 0x04, 0x80, 0x72, 0x81, 0x09, 0x24, 0x06, 0x07, 0x02, 0x00, 0x81,
+ 0x0F, 0x04, 0x80, 0x66, 0x81, 0x2D, 0x24, 0x06, 0x13, 0x02, 0x00, 0x06,
+ 0x0A, 0x01, 0x00, 0x03, 0x01, 0x81, 0x0D, 0x03, 0x01, 0x04, 0x02, 0x81,
+ 0x2B, 0x04, 0x80, 0x4E, 0x6C, 0x24, 0x06, 0x05, 0x81, 0x2B, 0x04, 0x80,
+ 0x45, 0x81, 0x30, 0x24, 0x06, 0x04, 0x81, 0x2B, 0x04, 0x3C, 0x81, 0x08,
+ 0x24, 0x06, 0x04, 0x81, 0x2B, 0x04, 0x33, 0x81, 0x2E, 0x24, 0x06, 0x04,
+ 0x81, 0x2B, 0x04, 0x2A, 0x76, 0x24, 0x06, 0x04, 0x81, 0x2B, 0x04, 0x22,
+ 0x81, 0x00, 0x24, 0x06, 0x04, 0x81, 0x2B, 0x04, 0x19, 0x6B, 0x24, 0x06,
+ 0x04, 0x81, 0x2B, 0x04, 0x11, 0x81, 0x2F, 0x24, 0x06, 0x04, 0x81, 0x2B,
+ 0x04, 0x08, 0x02, 0x08, 0x06, 0x02, 0x46, 0x26, 0x81, 0x2B, 0x75, 0x75,
+ 0x04, 0xFE, 0x54, 0x75, 0x75, 0x04, 0x08, 0x01, 0x7F, 0x11, 0x05, 0x02,
+ 0x53, 0x26, 0x22, 0x75, 0x38, 0x02, 0x00, 0x06, 0x08, 0x02, 0x01, 0x3A,
+ 0x2D, 0x05, 0x02, 0x42, 0x26, 0x02, 0x00, 0x06, 0x01, 0x17, 0x02, 0x00,
+ 0x02, 0x07, 0x2D, 0x05, 0x02, 0x4E, 0x26, 0x81, 0x20, 0x72, 0x81, 0x1B,
+ 0x81, 0x11, 0x06, 0x81, 0x07, 0x81, 0x25, 0x24, 0x06, 0x08, 0x01, 0x02,
+ 0x58, 0x81, 0x02, 0x04, 0x80, 0x6C, 0x81, 0x26, 0x24, 0x06, 0x08, 0x01,
+ 0x03, 0x58, 0x81, 0x03, 0x04, 0x80, 0x5F, 0x81, 0x27, 0x24, 0x06, 0x08,
+ 0x01, 0x04, 0x58, 0x81, 0x04, 0x04, 0x80, 0x52, 0x81, 0x28, 0x24, 0x06,
+ 0x08, 0x01, 0x05, 0x58, 0x81, 0x05, 0x04, 0x80, 0x45, 0x81, 0x29, 0x24,
+ 0x06, 0x07, 0x01, 0x06, 0x58, 0x81, 0x06, 0x04, 0x39, 0x7B, 0x24, 0x06,
+ 0x07, 0x01, 0x02, 0x57, 0x81, 0x02, 0x04, 0x2E, 0x7C, 0x24, 0x06, 0x07,
+ 0x01, 0x03, 0x57, 0x81, 0x03, 0x04, 0x23, 0x7D, 0x24, 0x06, 0x07, 0x01,
+ 0x04, 0x57, 0x81, 0x04, 0x04, 0x18, 0x7E, 0x24, 0x06, 0x07, 0x01, 0x05,
+ 0x57, 0x81, 0x05, 0x04, 0x0D, 0x7F, 0x24, 0x06, 0x07, 0x01, 0x06, 0x57,
+ 0x81, 0x06, 0x04, 0x02, 0x54, 0x26, 0x5C, 0x33, 0x5E, 0x35, 0x1B, 0x23,
+ 0x05, 0x02, 0x54, 0x26, 0x5B, 0x35, 0x04, 0x02, 0x54, 0x26, 0x81, 0x2A,
+ 0x81, 0x12, 0x23, 0x01, T0_INT2(BR_X509_BUFSIZE_SIG), 0x12, 0x06, 0x02,
+ 0x4D, 0x26, 0x23, 0x5D, 0x33, 0x5A, 0x81, 0x13, 0x75, 0x75, 0x01, 0x00,
+ 0x59, 0x34, 0x18, 0x00, 0x00, 0x01, 0x30, 0x0A, 0x23, 0x01, 0x00, 0x01,
+ 0x09, 0x6F, 0x05, 0x02, 0x45, 0x26, 0x00, 0x00, 0x2E, 0x2E, 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,
+ 0x00, 0x01, 0x82, 0x04, 0x00, 0x00, 0x01, 0x80, 0x6B, 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, 0x2E,
+ 0x11, 0x06, 0x07, 0x3F, 0x81, 0x1B, 0x81, 0x2A, 0x81, 0x21, 0x00, 0x00,
+ 0x01, 0x81, 0x78, 0x00, 0x00, 0x01, 0x81, 0x68, 0x00, 0x00, 0x01, 0x7F,
+ 0x78, 0x19, 0x01, 0x00, 0x78, 0x19, 0x04, 0x7A, 0x00, 0x01, 0x81, 0x34,
+ 0x00, 0x01, 0x7A, 0x0D, 0x06, 0x02, 0x4C, 0x26, 0x23, 0x03, 0x00, 0x0A,
+ 0x02, 0x00, 0x00, 0x01, 0x01, 0x00, 0x03, 0x00, 0x81, 0x1D, 0x23, 0x06,
+ 0x18, 0x81, 0x20, 0x01, 0x22, 0x11, 0x06, 0x0C, 0x71, 0x81, 0x1F, 0x22,
+ 0x2B, 0x02, 0x00, 0x2D, 0x03, 0x00, 0x04, 0x03, 0x22, 0x81, 0x1C, 0x04,
+ 0x65, 0x75, 0x02, 0x00, 0x00, 0x00, 0x81, 0x1D, 0x81, 0x21, 0x23, 0x01,
+ 0x01, 0x11, 0x06, 0x0A, 0x81, 0x14, 0x05, 0x02, 0x4E, 0x26, 0x81, 0x21,
+ 0x04, 0x02, 0x4E, 0x26, 0x23, 0x01, 0x02, 0x11, 0x06, 0x0E, 0x22, 0x71,
+ 0x81, 0x1E, 0x64, 0x29, 0x3E, 0x0D, 0x06, 0x02, 0x4E, 0x26, 0x81, 0x21,
+ 0x01, 0x7F, 0x10, 0x06, 0x02, 0x53, 0x26, 0x22, 0x75, 0x00, 0x02, 0x06,
+ 0x10, 0x60, 0x2A, 0x01, 0x10, 0x15, 0x06, 0x04, 0x01, 0x30, 0x04, 0x03,
+ 0x01, 0x81, 0x40, 0x04, 0x02, 0x01, 0x04, 0x03, 0x00, 0x81, 0x20, 0x01,
+ 0x03, 0x74, 0x81, 0x1B, 0x81, 0x22, 0x03, 0x01, 0x02, 0x01, 0x01, 0x07,
+ 0x12, 0x06, 0x02, 0x53, 0x26, 0x23, 0x01, 0x00, 0x2E, 0x11, 0x06, 0x05,
+ 0x22, 0x4A, 0x26, 0x04, 0x17, 0x01, 0x01, 0x2E, 0x11, 0x06, 0x0B, 0x22,
+ 0x81, 0x22, 0x02, 0x01, 0x14, 0x02, 0x01, 0x0E, 0x04, 0x06, 0x22, 0x81,
+ 0x22, 0x01, 0x00, 0x22, 0x02, 0x00, 0x15, 0x05, 0x02, 0x4A, 0x26, 0x81,
+ 0x2A, 0x00, 0x02, 0x36, 0x01, 0x00, 0x65, 0x35, 0x81, 0x1D, 0x23, 0x06,
+ 0x80, 0x6F, 0x81, 0x20, 0x01, 0x11, 0x73, 0x81, 0x1B, 0x23, 0x05, 0x02,
+ 0x41, 0x26, 0x23, 0x06, 0x80, 0x5B, 0x81, 0x1D, 0x81, 0x20, 0x01, 0x06,
+ 0x74, 0x81, 0x1B, 0x23, 0x01, 0x03, 0x11, 0x06, 0x1E, 0x81, 0x22, 0x01,
+ 0x10, 0x0E, 0x03, 0x00, 0x81, 0x22, 0x01, 0x08, 0x0E, 0x02, 0x00, 0x09,
+ 0x03, 0x00, 0x81, 0x22, 0x02, 0x00, 0x09, 0x01, 0x82, 0xD4, 0x88, 0x03,
+ 0x11, 0x03, 0x01, 0x81, 0x2A, 0x02, 0x01, 0x06, 0x23, 0x81, 0x20, 0x23,
+ 0x23, 0x01, 0x0C, 0x11, 0x39, 0x01, 0x13, 0x11, 0x2D, 0x39, 0x01, 0x14,
+ 0x11, 0x2D, 0x06, 0x07, 0x71, 0x81, 0x1F, 0x22, 0x75, 0x04, 0x07, 0x22,
+ 0x01, 0x00, 0x65, 0x35, 0x81, 0x2A, 0x04, 0x02, 0x81, 0x2A, 0x04, 0xFF,
+ 0x21, 0x75, 0x04, 0xFF, 0x0D, 0x75, 0x1A, 0x00, 0x00, 0x81, 0x20, 0x01,
+ 0x06, 0x74, 0x81, 0x1F, 0x00, 0x00, 0x81, 0x20, 0x01, 0x03, 0x74, 0x81,
+ 0x1B, 0x81, 0x22, 0x06, 0x02, 0x52, 0x26, 0x00, 0x00, 0x39, 0x23, 0x06,
+ 0x07, 0x2F, 0x23, 0x06, 0x01, 0x19, 0x04, 0x76, 0x3F, 0x00, 0x00, 0x01,
+ 0x01, 0x74, 0x81, 0x1A, 0x01, 0x01, 0x10, 0x06, 0x02, 0x40, 0x26, 0x81,
+ 0x22, 0x3B, 0x00, 0x04, 0x81, 0x20, 0x23, 0x01, 0x17, 0x01, 0x18, 0x6F,
+ 0x05, 0x02, 0x45, 0x26, 0x01, 0x18, 0x11, 0x03, 0x00, 0x71, 0x81, 0x1B,
+ 0x81, 0x16, 0x02, 0x00, 0x06, 0x0D, 0x01, 0x80, 0x64, 0x08, 0x03, 0x01,
+ 0x81, 0x16, 0x02, 0x01, 0x09, 0x04, 0x0E, 0x23, 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, 0x81, 0x17, 0x3E, 0x01, 0x01, 0x0E,
+ 0x02, 0x01, 0x01, 0x04, 0x07, 0x3C, 0x02, 0x01, 0x01, 0x80, 0x64, 0x07,
+ 0x3B, 0x02, 0x01, 0x01, 0x83, 0x10, 0x07, 0x3C, 0x2D, 0x15, 0x06, 0x03,
+ 0x01, 0x18, 0x09, 0x81, 0x0B, 0x09, 0x77, 0x23, 0x01, 0x05, 0x14, 0x02,
+ 0x03, 0x09, 0x03, 0x03, 0x01, 0x1F, 0x15, 0x01, 0x01, 0x39, 0x81, 0x17,
+ 0x02, 0x03, 0x09, 0x3E, 0x03, 0x03, 0x01, 0x00, 0x01, 0x17, 0x81, 0x17,
+ 0x01, 0x9C, 0x10, 0x08, 0x03, 0x02, 0x01, 0x00, 0x01, 0x3B, 0x81, 0x17,
+ 0x01, 0x3C, 0x08, 0x02, 0x02, 0x09, 0x03, 0x02, 0x01, 0x00, 0x01, 0x3C,
+ 0x81, 0x17, 0x02, 0x02, 0x09, 0x03, 0x02, 0x81, 0x22, 0x23, 0x01, 0x2E,
+ 0x11, 0x06, 0x0E, 0x22, 0x81, 0x22, 0x23, 0x01, 0x30, 0x01, 0x39, 0x6F,
+ 0x06, 0x03, 0x22, 0x04, 0x73, 0x01, 0x80, 0x5A, 0x10, 0x06, 0x02, 0x45,
+ 0x26, 0x75, 0x02, 0x03, 0x02, 0x02, 0x00, 0x01, 0x81, 0x22, 0x79, 0x01,
+ 0x0A, 0x08, 0x03, 0x00, 0x81, 0x22, 0x79, 0x02, 0x00, 0x09, 0x00, 0x02,
+ 0x03, 0x00, 0x03, 0x01, 0x81, 0x16, 0x23, 0x02, 0x01, 0x02, 0x00, 0x6F,
+ 0x05, 0x02, 0x45, 0x26, 0x00, 0x00, 0x32, 0x81, 0x20, 0x01, 0x02, 0x74,
+ 0x0B, 0x81, 0x19, 0x00, 0x03, 0x23, 0x03, 0x00, 0x03, 0x01, 0x03, 0x02,
+ 0x81, 0x1B, 0x81, 0x22, 0x23, 0x01, 0x81, 0x00, 0x13, 0x06, 0x02, 0x51,
+ 0x26, 0x23, 0x01, 0x00, 0x11, 0x06, 0x0C, 0x22, 0x23, 0x05, 0x04, 0x22,
+ 0x01, 0x00, 0x00, 0x81, 0x22, 0x04, 0x6E, 0x02, 0x01, 0x23, 0x05, 0x02,
+ 0x4D, 0x26, 0x3E, 0x03, 0x01, 0x02, 0x02, 0x35, 0x02, 0x02, 0x3D, 0x03,
+ 0x02, 0x23, 0x06, 0x04, 0x81, 0x22, 0x04, 0x67, 0x22, 0x02, 0x00, 0x02,
+ 0x01, 0x0A, 0x00, 0x01, 0x81, 0x22, 0x23, 0x01, 0x81, 0x00, 0x0D, 0x06,
+ 0x01, 0x00, 0x01, 0x81, 0x00, 0x0A, 0x23, 0x05, 0x02, 0x4B, 0x26, 0x03,
+ 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x12, 0x06, 0x1A, 0x02, 0x00,
+ 0x3E, 0x03, 0x00, 0x23, 0x01, 0x87, 0xFF, 0xFF, 0x7F, 0x12, 0x06, 0x02,
+ 0x4C, 0x26, 0x01, 0x08, 0x0E, 0x39, 0x81, 0x22, 0x32, 0x09, 0x04, 0x5F,
+ 0x00, 0x00, 0x81, 0x1A, 0x81, 0x0C, 0x00, 0x00, 0x81, 0x1B, 0x81, 0x2A,
+ 0x00, 0x00, 0x81, 0x20, 0x72, 0x81, 0x1B, 0x00, 0x01, 0x81, 0x1B, 0x23,
+ 0x05, 0x02, 0x51, 0x26, 0x81, 0x22, 0x23, 0x01, 0x81, 0x00, 0x13, 0x06,
+ 0x02, 0x51, 0x26, 0x03, 0x00, 0x23, 0x06, 0x17, 0x81, 0x22, 0x02, 0x00,
+ 0x23, 0x01, 0x87, 0xFF, 0xFF, 0x7F, 0x13, 0x06, 0x02, 0x51, 0x26, 0x01,
+ 0x08, 0x0E, 0x09, 0x03, 0x00, 0x04, 0x66, 0x22, 0x02, 0x00, 0x00, 0x00,
+ 0x81, 0x1B, 0x23, 0x01, 0x81, 0x7F, 0x12, 0x06, 0x09, 0x81, 0x2A, 0x01,
+ 0x00, 0x65, 0x35, 0x01, 0x00, 0x00, 0x23, 0x65, 0x35, 0x65, 0x3D, 0x81,
+ 0x13, 0x01, 0x7F, 0x00, 0x01, 0x81, 0x22, 0x03, 0x00, 0x02, 0x00, 0x01,
+ 0x05, 0x14, 0x01, 0x01, 0x15, 0x2C, 0x02, 0x00, 0x01, 0x06, 0x14, 0x23,
+ 0x01, 0x01, 0x15, 0x06, 0x02, 0x43, 0x26, 0x01, 0x04, 0x0E, 0x02, 0x00,
+ 0x01, 0x1F, 0x15, 0x23, 0x01, 0x1F, 0x11, 0x06, 0x02, 0x44, 0x26, 0x09,
+ 0x00, 0x00, 0x23, 0x05, 0x05, 0x01, 0x00, 0x01, 0x7F, 0x00, 0x81, 0x20,
+ 0x00, 0x00, 0x23, 0x05, 0x02, 0x4C, 0x26, 0x3E, 0x81, 0x23, 0x00, 0x00,
+ 0x30, 0x23, 0x01, 0x00, 0x13, 0x06, 0x01, 0x00, 0x22, 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, 0x81, 0x2B, 0x22, 0x00, 0x00, 0x23, 0x06, 0x08, 0x81, 0x2C, 0x23,
+ 0x06, 0x01, 0x19, 0x04, 0x75, 0x00, 0x00, 0x01, 0x00, 0x2E, 0x2F, 0x0B,
+ 0x3F, 0x00, 0x00, 0x01, 0x81, 0x6C, 0x00, 0x00, 0x01, 0x81, 0x7C, 0x00,
+ 0x00, 0x01, 0x82, 0x11, 0x00, 0x00, 0x01, 0x81, 0x74, 0x00, 0x00, 0x01,
+ 0x03, 0x31, 0x01, 0x03, 0x31, 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,
+ 92,
+ 96,
+ 100,
+ 104,
+ 108,
+ 112,
+ 116,
+ 120,
+ 124,
+ 129,
+ 134,
+ 139,
+ 144,
+ 149,
+ 154,
+ 159,
+ 164,
+ 172,
+ 177,
+ 182,
+ 187,
+ 192,
+ 197,
+ 202,
+ 207,
+ 212,
+ 217,
+ 222,
+ 227,
+ 232,
+ 261,
+ 276,
+ 282,
+ 288,
+ 293,
+ 301,
+ 309,
+ 315,
+ 320,
+ 331,
+ 1053,
+ 1068,
+ 1072,
+ 1077,
+ 1082,
+ 1087,
+ 1092,
+ 1097,
+ 1102,
+ 1107,
+ 1111,
+ 1116,
+ 1121,
+ 1126,
+ 1131,
+ 1144,
+ 1149,
+ 1154,
+ 1165,
+ 1170,
+ 1184,
+ 1222,
+ 1275,
+ 1363,
+ 1489,
+ 1498,
+ 1513,
+ 1527,
+ 1544,
+ 1776,
+ 1792,
+ 1810,
+ 1821,
+ 1892,
+ 1950,
+ 1956,
+ 1962,
+ 1969,
+ 2020,
+ 2049,
+ 2094,
+ 2106,
+ 2116,
+ 2129,
+ 2133,
+ 2137,
+ 2141,
+ 2145,
+ 2149,
+ 2153,
+ 2158,
+ 2171,
+ 2179,
+ 2184,
+ 2189,
+ 2194,
+ 2199
+};
+
+#define T0_INTERPRETED 59
+
+#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, 138)
+
+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() break
+
+ dp = ((t0_context *)t0ctx)->dp;
+ rp = ((t0_context *)t0ctx)->rp;
+ ip = ((t0_context *)t0ctx)->ip;
+ for (;;) {
+ uint32_t t0x;
+
+ t0x = t0_parse7E_unsigned(&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, 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, 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: {
+ /* data-get8 */
+
+ size_t addr = T0_POP();
+ T0_PUSH(t0_datablock[addr]);
+
+ }
+ break;
+ case 31: {
+ /* dn-hash-length */
+
+ T0_PUSH(DNHASH_LEN);
+
+ }
+ break;
+ case 32: {
+ /* 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 33: {
+ /* 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 34: {
+ /* drop */
+ (void)T0_POP();
+ }
+ break;
+ case 35: {
+ /* dup */
+ T0_PUSH(T0_PEEK(0));
+ }
+ break;
+ case 36: {
+ /* 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 37: {
+ /* 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 38: {
+ /* fail */
+
+ CTX->err = T0_POPi();
+ T0_CO();
+
+ }
+ break;
+ case 39: {
+ /* 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 40: {
+ /* get16 */
+
+ uint32_t addr = T0_POP();
+ T0_PUSH(*(uint16_t *)((unsigned char *)CTX + addr));
+
+ }
+ break;
+ case 41: {
+ /* get32 */
+
+ uint32_t addr = T0_POP();
+ T0_PUSH(*(uint32_t *)((unsigned char *)CTX + addr));
+
+ }
+ break;
+ case 42: {
+ /* get8 */
+
+ uint32_t addr = T0_POP();
+ T0_PUSH(*((unsigned char *)CTX + addr));
+
+ }
+ break;
+ case 43: {
+ /* 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 44: {
+ /* neg */
+
+ uint32_t a = T0_POP();
+ T0_PUSH(-a);
+
+ }
+ break;
+ case 45: {
+ /* or */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a | b);
+
+ }
+ break;
+ case 46: {
+ /* over */
+ T0_PUSH(T0_PEEK(1));
+ }
+ break;
+ case 47: {
+ /* 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 48: {
+ /* 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 49: {
+ /* roll */
+ T0_ROLL(T0_POP());
+ }
+ break;
+ case 50: {
+ /* rot */
+ T0_ROT();
+ }
+ break;
+ case 51: {
+ /* set16 */
+
+ uint32_t addr = T0_POP();
+ *(uint16_t *)((unsigned char *)CTX + addr) = T0_POP();
+
+ }
+ break;
+ case 52: {
+ /* set32 */
+
+ uint32_t addr = T0_POP();
+ *(uint32_t *)((unsigned char *)CTX + addr) = T0_POP();
+
+ }
+ break;
+ case 53: {
+ /* set8 */
+
+ uint32_t addr = T0_POP();
+ *((unsigned char *)CTX + addr) = (unsigned char)T0_POP();
+
+ }
+ break;
+ case 54: {
+ /* start-dn-hash */
+
+ CTX->dn_hash_impl->init(&CTX->dn_hash.vtable);
+ CTX->do_dn_hash = 1;
+
+ }
+ break;
+ case 55: {
+ /* start-tbs-hash */
+
+ br_multihash_init(&CTX->mhash);
+ CTX->do_mhash = 1;
+
+ }
+ break;
+ case 56: {
+ /* stop-tbs-hash */
+
+ CTX->do_mhash = 0;
+
+ }
+ break;
+ case 57: {
+ /* swap */
+ T0_SWAP();
+ }
+ break;
+ case 58: {
+ /* 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;
+}
--- /dev/null
+\ 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.
+ */
+
+#ifndef BR_USE_UNIX_TIME
+#if defined __unix__ || defined __linux__ \
+ || defined _POSIX_SOURCE || defined _POSIX_C_SOURCE \
+ || (defined __APPLE__ && defined __MACH__)
+#define BR_USE_UNIX_TIME 1
+#endif
+#endif
+
+#ifndef BR_USE_WIN32_TIME
+#if defined _WIN32 || defined _WIN64
+#define BR_USE_WIN32_TIME 1
+#endif
+#endif
+
+#if BR_USE_UNIX_TIME
+#include <time.h>
+#endif
+
+#if BR_USE_WIN32_TIME
+#include <windows.h>
+#endif
+
+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,
+ unsigned expected_key_type, const char *server_name)
+{
+ br_x509_minimal_context *cc;
+
+ cc = (br_x509_minimal_context *)ctx;
+ 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);
+ cc->expected_key_type = expected_key_type;
+ 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 *)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 *)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 *)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 *)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)
+{
+ br_x509_minimal_context *cc;
+
+ cc = (br_x509_minimal_context *)ctx;
+ if (cc->err == BR_ERR_X509_OK
+ || cc->err == BR_ERR_X509_NOT_TRUSTED)
+ {
+ return &((br_x509_minimal_context *)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 *)((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;
+}
+
+/*
+ * 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;
+ }
+}
+
+/*
+ * 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;
+}
+
+}
+
+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: expected_key_type
+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. The normalized DN hash is computed and stored in the
+\ current_dn_hash. The Common Name is also extracted to the pad, if
+\ it is present and small enough (255 bytes at most); the CN length is
+\ then written in pad[0]. If these conditions are not met, then pad[0]
+\ is set to 0.
+: read-DN ( lim -- lim )
+ \ Activate DN hashing.
+ start-dn-hash
+
+ \ Prepare pad.
+ 0 addr-pad set8
+
+ \ 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
+ \ We want to recognize the OID for Common Name,
+ \ but we don't want to use read-OID because we
+ \ need to preserve the pad contents. Instead, we
+ \ use the fact that the encoding for the value of
+ \ id-at-commonName is 55 04 03 (three bytes).
+ read-tag 0x06 check-tag-primitive read-length-open-elt
+ dup 3 = if
+ read8 16 << { tmp }
+ read8 8 << tmp + >tmp
+ read8 tmp +
+ 0x550403 = { isCN }
+ then
+ skip-close-elt
+
+ \ If this is a Common Name, then we want to copy
+ \ it to the pad, but only if it uses a mono-byte
+ \ encoding (Printable, Teletex or UTF-8).
+ isCN if
+ read-tag
+ dup dup 0x0C = swap 0x13 = or swap 0x14 = or if
+ check-primitive
+ read-small-value drop
+ close-elt
+ else
+ drop
+ 0 addr-pad set8
+ skip-close-elt
+ then
+ else
+ skip-close-elt
+ then
+ repeat
+ close-elt
+ repeat
+ close-elt
+
+ \ Compute DN hash and deactivate DN hashing.
+ compute-dn-hash ;
+
+\ 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, 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, 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
+
+\ 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 expected key usage is "key exchange", then the extension
+\ must contain either keyEncipherment (2) or dataEncipherment (3);
+\ -- if the expected key usage is "signature", then the extension
+\ must contain either digitalSignature (0) or nonRepudiation (1).
+\ For CA certificates, the extension must contain keyCertSign (5).
+: process-keyUsage ( lim ee -- lim )
+ \ Compute flags, depending on EE status and expected key usage.
+ \ This is a mask of bits in the first byte.
+ if
+ addr-expected_key_type get8 0x10 and if 0x30 else 0xC0 then
+ else
+ 0x04
+ then
+ { mask }
+ \ 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
+ mask and ifnot ERR_X509_FORBIDDEN_KEY_USAGE fail then
+ skip-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
+ \ 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.
+ read-DN
+ ee if
+ \ For the EE, we must check whether the Common Name, if
+ \ any, matches the expected server name.
+ match-server-name { eename }
+ else
+ \ For a non-EE certificate, the hashed subject DN must match
+ \ the saved hashed issuer DN from the previous certificate.
+ 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, check that the key type
+ \ matches that which was expected, then copy the
+ \ data to the relevant buffer.
+ addr-expected_key_type get8 0x0F and
+ dup if
+ pkey-type = ifnot ERR_X509_WRONG_KEY_TYPE fail then
+ else
+ drop
+ then
+ 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
+
+ \ 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
+ -1 decode-certificate
+ co
+ begin
+ 0 decode-certificate co
+ again
+ ;
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "bearssl.h"
+#include "inner.h"
+
+/*
+ * Decode an hexadecimal string. Returned value is the number of decoded
+ * bytes.
+ */
+static size_t
+hextobin(unsigned char *dst, const char *src)
+{
+ size_t num;
+ unsigned acc;
+ int z;
+
+ num = 0;
+ z = 0;
+ acc = 0;
+ while (*src != 0) {
+ int c = *src ++;
+ if (c >= '0' && c <= '9') {
+ c -= '0';
+ } else if (c >= 'A' && c <= 'F') {
+ c -= ('A' - 10); \
+ } else if (c >= 'a' && c <= 'f') {
+ c -= ('a' - 10); \
+ } else {
+ continue;
+ }
+ if (z) {
+ *dst ++ = (acc << 4) + c;
+ num ++;
+ } else {
+ acc = c;
+ }
+ z = !z;
+ }
+ return num;
+}
+
+static void
+check_equals(char *banner, const void *v1, const void *v2, size_t len)
+{
+ size_t u;
+ const unsigned char *b;
+
+ if (memcmp(v1, v2, len) == 0) {
+ return;
+ }
+ fprintf(stderr, "\n%s failed\n", banner);
+ fprintf(stderr, "v1: ");
+ for (u = 0, b = v1; u < len; u ++) {
+ fprintf(stderr, "%02X", b[u]);
+ }
+ fprintf(stderr, "\nv2: ");
+ for (u = 0, b = v2; u < len; u ++) {
+ fprintf(stderr, "%02X", b[u]);
+ }
+ fprintf(stderr, "\n");
+ exit(EXIT_FAILURE);
+}
+
+#define HASH_SIZE(cname) br_ ## cname ## _SIZE
+
+#define TEST_HASH(Name, cname) \
+static void \
+test_ ## cname ## _internal(char *data, char *refres) \
+{ \
+ br_ ## cname ## _context mc; \
+ unsigned char res[HASH_SIZE(cname)], ref[HASH_SIZE(cname)]; \
+ size_t u, n; \
+ \
+ hextobin(ref, refres); \
+ n = strlen(data); \
+ br_ ## cname ## _init(&mc); \
+ br_ ## cname ## _update(&mc, data, n); \
+ br_ ## cname ## _out(&mc, res); \
+ check_equals("KAT " #Name " 1", res, ref, HASH_SIZE(cname)); \
+ br_ ## cname ## _init(&mc); \
+ for (u = 0; u < n; u ++) { \
+ br_ ## cname ## _update(&mc, data + u, 1); \
+ } \
+ br_ ## cname ## _out(&mc, res); \
+ check_equals("KAT " #Name " 2", res, ref, HASH_SIZE(cname)); \
+ for (u = 0; u < n; u ++) { \
+ br_ ## cname ## _context mc2; \
+ br_ ## cname ## _init(&mc); \
+ br_ ## cname ## _update(&mc, data, u); \
+ mc2 = mc; \
+ br_ ## cname ## _update(&mc, data + u, n - u); \
+ br_ ## cname ## _out(&mc, res); \
+ check_equals("KAT " #Name " 3", res, ref, HASH_SIZE(cname)); \
+ br_ ## cname ## _update(&mc2, data + u, n - u); \
+ br_ ## cname ## _out(&mc2, res); \
+ check_equals("KAT " #Name " 4", res, ref, HASH_SIZE(cname)); \
+ } \
+ memset(&mc, 0, sizeof mc); \
+ memset(res, 0, sizeof res); \
+ br_ ## cname ## _vtable.init(&mc.vtable); \
+ mc.vtable->update(&mc.vtable, data, n); \
+ mc.vtable->out(&mc.vtable, res); \
+ check_equals("KAT " #Name " 5", res, ref, HASH_SIZE(cname)); \
+ memset(res, 0, sizeof res); \
+ mc.vtable->init(&mc.vtable); \
+ mc.vtable->update(&mc.vtable, data, n); \
+ mc.vtable->out(&mc.vtable, res); \
+ check_equals("KAT " #Name " 6", res, ref, HASH_SIZE(cname)); \
+}
+
+#define KAT_MILLION_A(Name, cname, refres) do { \
+ br_ ## cname ## _context mc; \
+ unsigned char buf[1000]; \
+ unsigned char res[HASH_SIZE(cname)], ref[HASH_SIZE(cname)]; \
+ int i; \
+ \
+ hextobin(ref, refres); \
+ memset(buf, 'a', sizeof buf); \
+ br_ ## cname ## _init(&mc); \
+ for (i = 0; i < 1000; i ++) { \
+ br_ ## cname ## _update(&mc, buf, sizeof buf); \
+ } \
+ br_ ## cname ## _out(&mc, res); \
+ check_equals("KAT " #Name " 5", res, ref, HASH_SIZE(cname)); \
+ } while (0)
+
+TEST_HASH(MD5, md5)
+TEST_HASH(SHA-1, sha1)
+TEST_HASH(SHA-224, sha224)
+TEST_HASH(SHA-256, sha256)
+TEST_HASH(SHA-384, sha384)
+TEST_HASH(SHA-512, sha512)
+
+static void
+test_MD5(void)
+{
+ printf("Test MD5: ");
+ fflush(stdout);
+ test_md5_internal("", "d41d8cd98f00b204e9800998ecf8427e");
+ test_md5_internal("a", "0cc175b9c0f1b6a831c399e269772661");
+ test_md5_internal("abc", "900150983cd24fb0d6963f7d28e17f72");
+ test_md5_internal("message digest", "f96b697d7cb7938d525a2f31aaf161d0");
+ test_md5_internal("abcdefghijklmnopqrstuvwxyz",
+ "c3fcd3d76192e4007dfb496cca67e13b");
+ test_md5_internal("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstu"
+ "vwxyz0123456789", "d174ab98d277d9f5a5611c2c9f419d9f");
+ test_md5_internal("1234567890123456789012345678901234567890123456789"
+ "0123456789012345678901234567890",
+ "57edf4a22be3c955ac49da2e2107b67a");
+ KAT_MILLION_A(MD5, md5,
+ "7707d6ae4e027c70eea2a935c2296f21");
+ printf("done.\n");
+ fflush(stdout);
+}
+
+static void
+test_SHA1(void)
+{
+ printf("Test SHA-1: ");
+ fflush(stdout);
+ test_sha1_internal("abc", "a9993e364706816aba3e25717850c26c9cd0d89d");
+ test_sha1_internal("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlm"
+ "nomnopnopq", "84983e441c3bd26ebaae4aa1f95129e5e54670f1");
+
+ KAT_MILLION_A(SHA-1, sha1,
+ "34aa973cd4c4daa4f61eeb2bdbad27316534016f");
+ printf("done.\n");
+ fflush(stdout);
+}
+
+static void
+test_SHA224(void)
+{
+ printf("Test SHA-224: ");
+ fflush(stdout);
+ test_sha224_internal("abc",
+ "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7");
+ test_sha224_internal("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlm"
+ "nomnopnopq",
+ "75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525");
+
+ KAT_MILLION_A(SHA-224, sha224,
+ "20794655980c91d8bbb4c1ea97618a4bf03f42581948b2ee4ee7ad67");
+ printf("done.\n");
+ fflush(stdout);
+}
+
+static void
+test_SHA256(void)
+{
+ printf("Test SHA-256: ");
+ fflush(stdout);
+ test_sha256_internal("abc",
+ "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad");
+ test_sha256_internal("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlm"
+ "nomnopnopq",
+ "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1");
+
+ KAT_MILLION_A(SHA-256, sha256,
+ "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0");
+ printf("done.\n");
+ fflush(stdout);
+}
+
+static void
+test_SHA384(void)
+{
+ printf("Test SHA-384: ");
+ fflush(stdout);
+ test_sha384_internal("abc",
+ "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded163"
+ "1a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7");
+ test_sha384_internal(
+ "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
+ "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
+ "09330c33f71147e83d192fc782cd1b4753111b173b3b05d2"
+ "2fa08086e3b0f712fcc7c71a557e2db966c3e9fa91746039");
+
+ KAT_MILLION_A(SHA-384, sha384,
+ "9d0e1809716474cb086e834e310a4a1ced149e9c00f24852"
+ "7972cec5704c2a5b07b8b3dc38ecc4ebae97ddd87f3d8985");
+ printf("done.\n");
+ fflush(stdout);
+}
+
+static void
+test_SHA512(void)
+{
+ printf("Test SHA-512: ");
+ fflush(stdout);
+ test_sha512_internal("abc",
+ "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a"
+ "2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f");
+ test_sha512_internal(
+ "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
+ "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
+ "8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018"
+ "501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909");
+
+ KAT_MILLION_A(SHA-512, sha512,
+ "e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973eb"
+ "de0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b");
+ printf("done.\n");
+ fflush(stdout);
+}
+
+static void
+test_MD5_SHA1(void)
+{
+ unsigned char buf[500], out[36], outM[16], outS[20];
+ unsigned char seed[1];
+ br_hmac_drbg_context rc;
+ br_md5_context mc;
+ br_sha1_context sc;
+ br_md5sha1_context cc;
+ size_t u;
+
+ printf("Test MD5+SHA-1: ");
+ fflush(stdout);
+
+ seed[0] = 0;
+ br_hmac_drbg_init(&rc, &br_sha256_vtable, seed, sizeof seed);
+ for (u = 0; u < sizeof buf; u ++) {
+ size_t v;
+
+ br_hmac_drbg_generate(&rc, buf, u);
+ br_md5_init(&mc);
+ br_md5_update(&mc, buf, u);
+ br_md5_out(&mc, outM);
+ br_sha1_init(&sc);
+ br_sha1_update(&sc, buf, u);
+ br_sha1_out(&sc, outS);
+ br_md5sha1_init(&cc);
+ br_md5sha1_update(&cc, buf, u);
+ br_md5sha1_out(&cc, out);
+ check_equals("MD5+SHA-1 [1]", out, outM, 16);
+ check_equals("MD5+SHA-1 [2]", out + 16, outS, 20);
+ br_md5sha1_init(&cc);
+ for (v = 0; v < u; v ++) {
+ br_md5sha1_update(&cc, buf + v, 1);
+ }
+ br_md5sha1_out(&cc, out);
+ check_equals("MD5+SHA-1 [3]", out, outM, 16);
+ check_equals("MD5+SHA-1 [4]", out + 16, outS, 20);
+ }
+
+ printf("done.\n");
+ fflush(stdout);
+}
+
+/*
+ * Compute a hash function, on some data, by ID. Returned value is
+ * hash output length.
+ */
+static size_t
+do_hash(int id, const void *data, size_t len, void *out)
+{
+ br_md5_context cmd5;
+ br_sha1_context csha1;
+ br_sha224_context csha224;
+ br_sha256_context csha256;
+ br_sha384_context csha384;
+ br_sha512_context csha512;
+
+ switch (id) {
+ case br_md5_ID:
+ br_md5_init(&cmd5);
+ br_md5_update(&cmd5, data, len);
+ br_md5_out(&cmd5, out);
+ return 16;
+ case br_sha1_ID:
+ br_sha1_init(&csha1);
+ br_sha1_update(&csha1, data, len);
+ br_sha1_out(&csha1, out);
+ return 20;
+ case br_sha224_ID:
+ br_sha224_init(&csha224);
+ br_sha224_update(&csha224, data, len);
+ br_sha224_out(&csha224, out);
+ return 28;
+ case br_sha256_ID:
+ br_sha256_init(&csha256);
+ br_sha256_update(&csha256, data, len);
+ br_sha256_out(&csha256, out);
+ return 32;
+ case br_sha384_ID:
+ br_sha384_init(&csha384);
+ br_sha384_update(&csha384, data, len);
+ br_sha384_out(&csha384, out);
+ return 48;
+ case br_sha512_ID:
+ br_sha512_init(&csha512);
+ br_sha512_update(&csha512, data, len);
+ br_sha512_out(&csha512, out);
+ return 64;
+ default:
+ fprintf(stderr, "Uknown hash function: %d\n", id);
+ exit(EXIT_FAILURE);
+ return 0;
+ }
+}
+
+/*
+ * Tests for a multihash. Returned value should be 258 multiplied by the
+ * number of hash functions implemented by the context.
+ */
+static int
+test_multihash_inner(br_multihash_context *mc)
+{
+ /*
+ * Try hashing messages for all lengths from 0 to 257 bytes
+ * (inclusive). Each attempt is done twice, with data input
+ * either in one go, or byte by byte. In the byte by byte
+ * test, intermediate result are obtained and checked.
+ */
+ size_t len;
+ unsigned char buf[258];
+ int i;
+ int tcount;
+
+ tcount = 0;
+ for (len = 0; len < sizeof buf; len ++) {
+ br_sha1_context sc;
+ unsigned char tmp[20];
+
+ br_sha1_init(&sc);
+ br_sha1_update(&sc, buf, len);
+ br_sha1_out(&sc, tmp);
+ buf[len] = tmp[0];
+ }
+ for (len = 0; len <= 257; len ++) {
+ size_t u;
+
+ br_multihash_init(mc);
+ br_multihash_update(mc, buf, len);
+ for (i = 1; i <= 6; i ++) {
+ unsigned char tmp[64], tmp2[64];
+ size_t olen, olen2;
+
+ olen = br_multihash_out(mc, i, tmp);
+ if (olen == 0) {
+ continue;
+ }
+ olen2 = do_hash(i, buf, len, tmp2);
+ if (olen != olen2) {
+ fprintf(stderr,
+ "Bad hash output length: %u / %u\n",
+ (unsigned)olen, (unsigned)olen2);
+ exit(EXIT_FAILURE);
+ }
+ check_equals("Hash output", tmp, tmp2, olen);
+ tcount ++;
+ }
+
+ br_multihash_init(mc);
+ for (u = 0; u < len; u ++) {
+ br_multihash_update(mc, buf + u, 1);
+ for (i = 1; i <= 6; i ++) {
+ unsigned char tmp[64], tmp2[64];
+ size_t olen, olen2;
+
+ olen = br_multihash_out(mc, i, tmp);
+ if (olen == 0) {
+ continue;
+ }
+ olen2 = do_hash(i, buf, u + 1, tmp2);
+ if (olen != olen2) {
+ fprintf(stderr, "Bad hash output"
+ " length: %u / %u\n",
+ (unsigned)olen,
+ (unsigned)olen2);
+ exit(EXIT_FAILURE);
+ }
+ check_equals("Hash output", tmp, tmp2, olen);
+ }
+ }
+ }
+ return tcount;
+}
+
+static void
+test_multihash(void)
+{
+ br_multihash_context mc;
+
+ printf("Test MultiHash: ");
+ fflush(stdout);
+
+ br_multihash_zero(&mc);
+ br_multihash_setimpl(&mc, br_md5_ID, &br_md5_vtable);
+ if (test_multihash_inner(&mc) != 258) {
+ fprintf(stderr, "Failed test count\n");
+ }
+ printf(".");
+ fflush(stdout);
+
+ br_multihash_zero(&mc);
+ br_multihash_setimpl(&mc, br_sha1_ID, &br_sha1_vtable);
+ if (test_multihash_inner(&mc) != 258) {
+ fprintf(stderr, "Failed test count\n");
+ }
+ printf(".");
+ fflush(stdout);
+
+ br_multihash_zero(&mc);
+ br_multihash_setimpl(&mc, br_sha224_ID, &br_sha224_vtable);
+ if (test_multihash_inner(&mc) != 258) {
+ fprintf(stderr, "Failed test count\n");
+ }
+ printf(".");
+ fflush(stdout);
+
+ br_multihash_zero(&mc);
+ br_multihash_setimpl(&mc, br_sha256_ID, &br_sha256_vtable);
+ if (test_multihash_inner(&mc) != 258) {
+ fprintf(stderr, "Failed test count\n");
+ }
+ printf(".");
+ fflush(stdout);
+
+ br_multihash_zero(&mc);
+ br_multihash_setimpl(&mc, br_sha384_ID, &br_sha384_vtable);
+ if (test_multihash_inner(&mc) != 258) {
+ fprintf(stderr, "Failed test count\n");
+ }
+ printf(".");
+ fflush(stdout);
+
+ br_multihash_zero(&mc);
+ br_multihash_setimpl(&mc, br_sha512_ID, &br_sha512_vtable);
+ if (test_multihash_inner(&mc) != 258) {
+ fprintf(stderr, "Failed test count\n");
+ }
+ printf(".");
+ fflush(stdout);
+
+ br_multihash_zero(&mc);
+ br_multihash_setimpl(&mc, br_md5_ID, &br_md5_vtable);
+ br_multihash_setimpl(&mc, br_sha1_ID, &br_sha1_vtable);
+ br_multihash_setimpl(&mc, br_sha224_ID, &br_sha224_vtable);
+ br_multihash_setimpl(&mc, br_sha256_ID, &br_sha256_vtable);
+ br_multihash_setimpl(&mc, br_sha384_ID, &br_sha384_vtable);
+ br_multihash_setimpl(&mc, br_sha512_ID, &br_sha512_vtable);
+ if (test_multihash_inner(&mc) != 258 * 6) {
+ fprintf(stderr, "Failed test count\n");
+ }
+ printf(".");
+ fflush(stdout);
+
+ printf("done.\n");
+ fflush(stdout);
+}
+
+static void
+do_KAT_HMAC_bin_bin(const br_hash_class *digest_class,
+ const void *key, size_t key_len,
+ const void *data, size_t data_len, const char *href)
+{
+ br_hmac_key_context kc;
+ br_hmac_context ctx;
+ unsigned char tmp[64], ref[64];
+ size_t u, len;
+
+ len = hextobin(ref, href);
+ br_hmac_key_init(&kc, digest_class, key, key_len);
+ br_hmac_init(&ctx, &kc, 0);
+ br_hmac_update(&ctx, data, data_len);
+ br_hmac_out(&ctx, tmp);
+ check_equals("KAT HMAC 1", tmp, ref, len);
+
+ br_hmac_init(&ctx, &kc, 0);
+ for (u = 0; u < data_len; u ++) {
+ br_hmac_update(&ctx, (const unsigned char *)data + u, 1);
+ }
+ br_hmac_out(&ctx, tmp);
+ check_equals("KAT HMAC 2", tmp, ref, len);
+
+ for (u = 0; u < data_len; u ++) {
+ br_hmac_init(&ctx, &kc, 0);
+ br_hmac_update(&ctx, data, u);
+ br_hmac_out(&ctx, tmp);
+ br_hmac_update(&ctx,
+ (const unsigned char *)data + u, data_len - u);
+ br_hmac_out(&ctx, tmp);
+ check_equals("KAT HMAC 3", tmp, ref, len);
+ }
+}
+
+static void
+do_KAT_HMAC_str_str(const br_hash_class *digest_class, const char *key,
+ const char *data, const char *href)
+{
+ do_KAT_HMAC_bin_bin(digest_class, key, strlen(key),
+ data, strlen(data), href);
+}
+
+static void
+do_KAT_HMAC_hex_hex(const br_hash_class *digest_class, const char *skey,
+ const char *sdata, const char *href)
+{
+ unsigned char key[1024];
+ unsigned char data[1024];
+
+ do_KAT_HMAC_bin_bin(digest_class, key, hextobin(key, skey),
+ data, hextobin(data, sdata), href);
+}
+
+static void
+do_KAT_HMAC_hex_str(const br_hash_class *digest_class,
+ const char *skey, const char *data, const char *href)
+{
+ unsigned char key[1024];
+
+ do_KAT_HMAC_bin_bin(digest_class, key, hextobin(key, skey),
+ data, strlen(data), href);
+}
+
+static void
+test_HMAC_CT(const br_hash_class *digest_class,
+ const void *key, size_t key_len, const void *data)
+{
+ br_hmac_key_context kc;
+ br_hmac_context hc1, hc2;
+ unsigned char buf1[64], buf2[64];
+ size_t u, v;
+
+ br_hmac_key_init(&kc, digest_class, key, key_len);
+
+ for (u = 0; u < 130; u ++) {
+ for (v = 0; v < 130; v ++) {
+ size_t min_len, max_len;
+ size_t w;
+
+ min_len = v;
+ max_len = v + 256;
+ for (w = min_len; w <= max_len; w ++) {
+ char tmp[30];
+ size_t hlen1, hlen2;
+
+ br_hmac_init(&hc1, &kc, 0);
+ br_hmac_update(&hc1, data, u + w);
+ hlen1 = br_hmac_out(&hc1, buf1);
+ br_hmac_init(&hc2, &kc, 0);
+ br_hmac_update(&hc2, data, u);
+ hlen2 = br_hmac_outCT(&hc2,
+ (const unsigned char *)data + u, w,
+ min_len, max_len, buf2);
+ if (hlen1 != hlen2) {
+ fprintf(stderr, "HMAC length mismatch:"
+ " %u / %u\n", (unsigned)hlen1,
+ (unsigned)hlen2);
+ exit(EXIT_FAILURE);
+ }
+ sprintf(tmp, "HMAC CT %u,%u,%u",
+ (unsigned)u, (unsigned)v, (unsigned)w);
+ check_equals(tmp, buf1, buf2, hlen1);
+ }
+ }
+ printf(".");
+ fflush(stdout);
+ }
+ printf(" ");
+ fflush(stdout);
+}
+
+static void
+test_HMAC(void)
+{
+ unsigned char data[1000];
+ unsigned x;
+ size_t u;
+ const char key[] = "test HMAC key";
+
+ printf("Test HMAC: ");
+ fflush(stdout);
+ do_KAT_HMAC_hex_str(&br_md5_vtable,
+ "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
+ "Hi There",
+ "9294727a3638bb1c13f48ef8158bfc9d");
+ do_KAT_HMAC_str_str(&br_md5_vtable,
+ "Jefe",
+ "what do ya want for nothing?",
+ "750c783e6ab0b503eaa86e310a5db738");
+ do_KAT_HMAC_hex_hex(&br_md5_vtable,
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
+ "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD",
+ "56be34521d144c88dbb8c733f0e8b3f6");
+ do_KAT_HMAC_hex_hex(&br_md5_vtable,
+ "0102030405060708090a0b0c0d0e0f10111213141516171819",
+ "CDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCD",
+ "697eaf0aca3a3aea3a75164746ffaa79");
+ do_KAT_HMAC_hex_str(&br_md5_vtable,
+ "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c",
+ "Test With Truncation",
+ "56461ef2342edc00f9bab995690efd4c");
+ do_KAT_HMAC_hex_str(&br_md5_vtable,
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
+ "Test Using Larger Than Block-Size Key - Hash Key First",
+ "6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd");
+ do_KAT_HMAC_hex_str(&br_md5_vtable,
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
+ "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data",
+ "6f630fad67cda0ee1fb1f562db3aa53e");
+
+ do_KAT_HMAC_hex_str(&br_sha1_vtable,
+ "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
+ "Hi There",
+ "b617318655057264e28bc0b6fb378c8ef146be00");
+ do_KAT_HMAC_str_str(&br_sha1_vtable,
+ "Jefe",
+ "what do ya want for nothing?",
+ "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79");
+ do_KAT_HMAC_hex_hex(&br_sha1_vtable,
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
+ "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD",
+ "125d7342b9ac11cd91a39af48aa17b4f63f175d3");
+ do_KAT_HMAC_hex_hex(&br_sha1_vtable,
+ "0102030405060708090a0b0c0d0e0f10111213141516171819",
+ "CDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCD",
+ "4c9007f4026250c6bc8414f9bf50c86c2d7235da");
+ do_KAT_HMAC_hex_str(&br_sha1_vtable,
+ "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c",
+ "Test With Truncation",
+ "4c1a03424b55e07fe7f27be1d58bb9324a9a5a04");
+ do_KAT_HMAC_hex_str(&br_sha1_vtable,
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
+ "Test Using Larger Than Block-Size Key - Hash Key First",
+ "aa4ae5e15272d00e95705637ce8a3b55ed402112");
+ do_KAT_HMAC_hex_str(&br_sha1_vtable,
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
+ "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data",
+ "e8e99d0f45237d786d6bbaa7965c7808bbff1a91");
+
+ /* From RFC 4231 */
+
+ do_KAT_HMAC_hex_hex(&br_sha224_vtable,
+ "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
+ "4869205468657265",
+ "896fb1128abbdf196832107cd49df33f"
+ "47b4b1169912ba4f53684b22");
+
+ do_KAT_HMAC_hex_hex(&br_sha256_vtable,
+ "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
+ "4869205468657265",
+ "b0344c61d8db38535ca8afceaf0bf12b"
+ "881dc200c9833da726e9376c2e32cff7");
+
+ do_KAT_HMAC_hex_hex(&br_sha384_vtable,
+ "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
+ "4869205468657265",
+ "afd03944d84895626b0825f4ab46907f"
+ "15f9dadbe4101ec682aa034c7cebc59c"
+ "faea9ea9076ede7f4af152e8b2fa9cb6");
+
+ do_KAT_HMAC_hex_hex(&br_sha512_vtable,
+ "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
+ "4869205468657265",
+ "87aa7cdea5ef619d4ff0b4241a1d6cb0"
+ "2379f4e2ce4ec2787ad0b30545e17cde"
+ "daa833b7d6b8a702038b274eaea3f4e4"
+ "be9d914eeb61f1702e696c203a126854");
+
+ do_KAT_HMAC_hex_hex(&br_sha224_vtable,
+ "4a656665",
+ "7768617420646f2079612077616e7420"
+ "666f72206e6f7468696e673f",
+ "a30e01098bc6dbbf45690f3a7e9e6d0f"
+ "8bbea2a39e6148008fd05e44");
+
+ do_KAT_HMAC_hex_hex(&br_sha256_vtable,
+ "4a656665",
+ "7768617420646f2079612077616e7420"
+ "666f72206e6f7468696e673f",
+ "5bdcc146bf60754e6a042426089575c7"
+ "5a003f089d2739839dec58b964ec3843");
+
+ do_KAT_HMAC_hex_hex(&br_sha384_vtable,
+ "4a656665",
+ "7768617420646f2079612077616e7420"
+ "666f72206e6f7468696e673f",
+ "af45d2e376484031617f78d2b58a6b1b"
+ "9c7ef464f5a01b47e42ec3736322445e"
+ "8e2240ca5e69e2c78b3239ecfab21649");
+
+ do_KAT_HMAC_hex_hex(&br_sha512_vtable,
+ "4a656665",
+ "7768617420646f2079612077616e7420"
+ "666f72206e6f7468696e673f",
+ "164b7a7bfcf819e2e395fbe73b56e0a3"
+ "87bd64222e831fd610270cd7ea250554"
+ "9758bf75c05a994a6d034f65f8f0e6fd"
+ "caeab1a34d4a6b4b636e070a38bce737");
+
+ do_KAT_HMAC_hex_hex(&br_sha224_vtable,
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaa",
+ "dddddddddddddddddddddddddddddddd"
+ "dddddddddddddddddddddddddddddddd"
+ "dddddddddddddddddddddddddddddddd"
+ "dddd",
+ "7fb3cb3588c6c1f6ffa9694d7d6ad264"
+ "9365b0c1f65d69d1ec8333ea");
+
+ do_KAT_HMAC_hex_hex(&br_sha256_vtable,
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaa",
+ "dddddddddddddddddddddddddddddddd"
+ "dddddddddddddddddddddddddddddddd"
+ "dddddddddddddddddddddddddddddddd"
+ "dddd",
+ "773ea91e36800e46854db8ebd09181a7"
+ "2959098b3ef8c122d9635514ced565fe");
+
+ do_KAT_HMAC_hex_hex(&br_sha384_vtable,
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaa",
+ "dddddddddddddddddddddddddddddddd"
+ "dddddddddddddddddddddddddddddddd"
+ "dddddddddddddddddddddddddddddddd"
+ "dddd",
+ "88062608d3e6ad8a0aa2ace014c8a86f"
+ "0aa635d947ac9febe83ef4e55966144b"
+ "2a5ab39dc13814b94e3ab6e101a34f27");
+
+ do_KAT_HMAC_hex_hex(&br_sha512_vtable,
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaa",
+ "dddddddddddddddddddddddddddddddd"
+ "dddddddddddddddddddddddddddddddd"
+ "dddddddddddddddddddddddddddddddd"
+ "dddd",
+ "fa73b0089d56a284efb0f0756c890be9"
+ "b1b5dbdd8ee81a3655f83e33b2279d39"
+ "bf3e848279a722c806b485a47e67c807"
+ "b946a337bee8942674278859e13292fb");
+
+ do_KAT_HMAC_hex_hex(&br_sha224_vtable,
+ "0102030405060708090a0b0c0d0e0f10"
+ "111213141516171819",
+ "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
+ "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
+ "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
+ "cdcd",
+ "6c11506874013cac6a2abc1bb382627c"
+ "ec6a90d86efc012de7afec5a");
+
+ do_KAT_HMAC_hex_hex(&br_sha256_vtable,
+ "0102030405060708090a0b0c0d0e0f10"
+ "111213141516171819",
+ "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
+ "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
+ "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
+ "cdcd",
+ "82558a389a443c0ea4cc819899f2083a"
+ "85f0faa3e578f8077a2e3ff46729665b");
+
+ do_KAT_HMAC_hex_hex(&br_sha384_vtable,
+ "0102030405060708090a0b0c0d0e0f10"
+ "111213141516171819",
+ "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
+ "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
+ "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
+ "cdcd",
+ "3e8a69b7783c25851933ab6290af6ca7"
+ "7a9981480850009cc5577c6e1f573b4e"
+ "6801dd23c4a7d679ccf8a386c674cffb");
+
+ do_KAT_HMAC_hex_hex(&br_sha512_vtable,
+ "0102030405060708090a0b0c0d0e0f10"
+ "111213141516171819",
+ "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
+ "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
+ "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
+ "cdcd",
+ "b0ba465637458c6990e5a8c5f61d4af7"
+ "e576d97ff94b872de76f8050361ee3db"
+ "a91ca5c11aa25eb4d679275cc5788063"
+ "a5f19741120c4f2de2adebeb10a298dd");
+
+ do_KAT_HMAC_hex_hex(&br_sha224_vtable,
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaa",
+ "54657374205573696e67204c61726765"
+ "72205468616e20426c6f636b2d53697a"
+ "65204b6579202d2048617368204b6579"
+ "204669727374",
+ "95e9a0db962095adaebe9b2d6f0dbce2"
+ "d499f112f2d2b7273fa6870e");
+
+ do_KAT_HMAC_hex_hex(&br_sha256_vtable,
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaa",
+ "54657374205573696e67204c61726765"
+ "72205468616e20426c6f636b2d53697a"
+ "65204b6579202d2048617368204b6579"
+ "204669727374",
+ "60e431591ee0b67f0d8a26aacbf5b77f"
+ "8e0bc6213728c5140546040f0ee37f54");
+
+ do_KAT_HMAC_hex_hex(&br_sha384_vtable,
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaa",
+ "54657374205573696e67204c61726765"
+ "72205468616e20426c6f636b2d53697a"
+ "65204b6579202d2048617368204b6579"
+ "204669727374",
+ "4ece084485813e9088d2c63a041bc5b4"
+ "4f9ef1012a2b588f3cd11f05033ac4c6"
+ "0c2ef6ab4030fe8296248df163f44952");
+
+ do_KAT_HMAC_hex_hex(&br_sha512_vtable,
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaa",
+ "54657374205573696e67204c61726765"
+ "72205468616e20426c6f636b2d53697a"
+ "65204b6579202d2048617368204b6579"
+ "204669727374",
+ "80b24263c7c1a3ebb71493c1dd7be8b4"
+ "9b46d1f41b4aeec1121b013783f8f352"
+ "6b56d037e05f2598bd0fd2215d6a1e52"
+ "95e64f73f63f0aec8b915a985d786598");
+
+ do_KAT_HMAC_hex_hex(&br_sha224_vtable,
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaa",
+ "54686973206973206120746573742075"
+ "73696e672061206c6172676572207468"
+ "616e20626c6f636b2d73697a65206b65"
+ "7920616e642061206c61726765722074"
+ "68616e20626c6f636b2d73697a652064"
+ "6174612e20546865206b6579206e6565"
+ "647320746f2062652068617368656420"
+ "6265666f7265206265696e6720757365"
+ "642062792074686520484d414320616c"
+ "676f726974686d2e",
+ "3a854166ac5d9f023f54d517d0b39dbd"
+ "946770db9c2b95c9f6f565d1");
+
+ do_KAT_HMAC_hex_hex(&br_sha256_vtable,
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaa",
+ "54686973206973206120746573742075"
+ "73696e672061206c6172676572207468"
+ "616e20626c6f636b2d73697a65206b65"
+ "7920616e642061206c61726765722074"
+ "68616e20626c6f636b2d73697a652064"
+ "6174612e20546865206b6579206e6565"
+ "647320746f2062652068617368656420"
+ "6265666f7265206265696e6720757365"
+ "642062792074686520484d414320616c"
+ "676f726974686d2e",
+ "9b09ffa71b942fcb27635fbcd5b0e944"
+ "bfdc63644f0713938a7f51535c3a35e2");
+
+ do_KAT_HMAC_hex_hex(&br_sha384_vtable,
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaa",
+ "54686973206973206120746573742075"
+ "73696e672061206c6172676572207468"
+ "616e20626c6f636b2d73697a65206b65"
+ "7920616e642061206c61726765722074"
+ "68616e20626c6f636b2d73697a652064"
+ "6174612e20546865206b6579206e6565"
+ "647320746f2062652068617368656420"
+ "6265666f7265206265696e6720757365"
+ "642062792074686520484d414320616c"
+ "676f726974686d2e",
+ "6617178e941f020d351e2f254e8fd32c"
+ "602420feb0b8fb9adccebb82461e99c5"
+ "a678cc31e799176d3860e6110c46523e");
+
+ do_KAT_HMAC_hex_hex(&br_sha512_vtable,
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaa",
+ "54686973206973206120746573742075"
+ "73696e672061206c6172676572207468"
+ "616e20626c6f636b2d73697a65206b65"
+ "7920616e642061206c61726765722074"
+ "68616e20626c6f636b2d73697a652064"
+ "6174612e20546865206b6579206e6565"
+ "647320746f2062652068617368656420"
+ "6265666f7265206265696e6720757365"
+ "642062792074686520484d414320616c"
+ "676f726974686d2e",
+ "e37b6a775dc87dbaa4dfa9f96e5e3ffd"
+ "debd71f8867289865df5a32d20cdc944"
+ "b6022cac3c4982b10d5eeb55c3e4de15"
+ "134676fb6de0446065c97440fa8c6a58");
+
+ for (x = 1, u = 0; u < sizeof data; u ++) {
+ data[u] = x;
+ x = (x * 45) % 257;
+ }
+ printf("(MD5) ");
+ test_HMAC_CT(&br_md5_vtable, key, sizeof key, data);
+ printf("(SHA-1) ");
+ test_HMAC_CT(&br_sha1_vtable, key, sizeof key, data);
+ printf("(SHA-224) ");
+ test_HMAC_CT(&br_sha224_vtable, key, sizeof key, data);
+ printf("(SHA-256) ");
+ test_HMAC_CT(&br_sha256_vtable, key, sizeof key, data);
+ printf("(SHA-384) ");
+ test_HMAC_CT(&br_sha384_vtable, key, sizeof key, data);
+ printf("(SHA-512) ");
+ test_HMAC_CT(&br_sha512_vtable, key, sizeof key, data);
+
+ printf("done.\n");
+ fflush(stdout);
+}
+
+static void
+test_HMAC_DRBG(void)
+{
+ br_hmac_drbg_context ctx;
+ unsigned char seed[42], tmp[30];
+ unsigned char ref1[30], ref2[30], ref3[30];
+ size_t seed_len;
+
+ printf("Test HMAC_DRBG: ");
+ fflush(stdout);
+
+ seed_len = hextobin(seed,
+ "009A4D6792295A7F730FC3F2B49CBC0F62E862272F"
+ "01795EDF0D54DB760F156D0DAC04C0322B3A204224");
+ hextobin(ref1,
+ "9305A46DE7FF8EB107194DEBD3FD48AA"
+ "20D5E7656CBE0EA69D2A8D4E7C67");
+ hextobin(ref2,
+ "C70C78608A3B5BE9289BE90EF6E81A9E"
+ "2C1516D5751D2F75F50033E45F73");
+ hextobin(ref3,
+ "475E80E992140567FCC3A50DAB90FE84"
+ "BCD7BB03638E9C4656A06F37F650");
+ br_hmac_drbg_init(&ctx, &br_sha256_vtable, seed, seed_len);
+ br_hmac_drbg_generate(&ctx, tmp, sizeof tmp);
+ check_equals("KAT HMAC_DRBG 1", tmp, ref1, sizeof tmp);
+ br_hmac_drbg_generate(&ctx, tmp, sizeof tmp);
+ check_equals("KAT HMAC_DRBG 2", tmp, ref2, sizeof tmp);
+ br_hmac_drbg_generate(&ctx, tmp, sizeof tmp);
+ check_equals("KAT HMAC_DRBG 3", tmp, ref3, sizeof tmp);
+
+ memset(&ctx, 0, sizeof ctx);
+ br_hmac_drbg_vtable.init(&ctx.vtable,
+ &br_sha256_vtable, seed, seed_len);
+ ctx.vtable->generate(&ctx.vtable, tmp, sizeof tmp);
+ check_equals("KAT HMAC_DRBG 4", tmp, ref1, sizeof tmp);
+ ctx.vtable->generate(&ctx.vtable, tmp, sizeof tmp);
+ check_equals("KAT HMAC_DRBG 5", tmp, ref2, sizeof tmp);
+ ctx.vtable->generate(&ctx.vtable, tmp, sizeof tmp);
+ check_equals("KAT HMAC_DRBG 6", tmp, ref3, sizeof tmp);
+
+ printf("done.\n");
+ fflush(stdout);
+}
+
+static void
+do_KAT_PRF(
+ void (*prf)(void *dst, size_t len,
+ const void *secret, size_t secret_len,
+ const char *label, const void *seed, size_t seed_len),
+ const char *ssecret, const char *label, const char *sseed,
+ const char *sref)
+{
+ unsigned char secret[100], seed[100], ref[500], out[500];
+ size_t secret_len, seed_len, ref_len;
+
+ secret_len = hextobin(secret, ssecret);
+ seed_len = hextobin(seed, sseed);
+ ref_len = hextobin(ref, sref);
+ prf(out, ref_len, secret, secret_len, label, seed, seed_len);
+ check_equals("TLS PRF KAT", out, ref, ref_len);
+}
+
+static void
+test_PRF(void)
+{
+ printf("Test TLS PRF: ");
+ fflush(stdout);
+
+ /*
+ * Test vector taken from an email that was on:
+ * http://www.imc.org/ietf-tls/mail-archive/msg01589.html
+ * but no longer exists there; a version archived in 2008
+ * can be found on http://www.archive.org/
+ */
+ do_KAT_PRF(&br_tls10_prf,
+ "abababababababababababababababababababababababababababababababababababababababababababababababab",
+ "PRF Testvector",
+ "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd",
+ "d3d4d1e349b5d515044666d51de32bab258cb521b6b053463e354832fd976754443bcf9a296519bc289abcbc1187e4ebd31e602353776c408aafb74cbc85eff69255f9788faa184cbb957a9819d84a5d7eb006eb459d3ae8de9810454b8b2d8f1afbc655a8c9a013");
+
+ /*
+ * Test vectors are taken from:
+ * https://www.ietf.org/mail-archive/web/tls/current/msg03416.html
+ */
+ do_KAT_PRF(&br_tls12_sha256_prf,
+ "9bbe436ba940f017b17652849a71db35",
+ "test label",
+ "a0ba9f936cda311827a6f796ffd5198c",
+ "e3f229ba727be17b8d122620557cd453c2aab21d07c3d495329b52d4e61edb5a6b301791e90d35c9c9a46b4e14baf9af0fa022f7077def17abfd3797c0564bab4fbc91666e9def9b97fce34f796789baa48082d122ee42c5a72e5a5110fff70187347b66");
+ do_KAT_PRF(&br_tls12_sha384_prf,
+ "b80b733d6ceefcdc71566ea48e5567df",
+ "test label",
+ "cd665cf6a8447dd6ff8b27555edb7465",
+ "7b0c18e9ced410ed1804f2cfa34a336a1c14dffb4900bb5fd7942107e81c83cde9ca0faa60be9fe34f82b1233c9146a0e534cb400fed2700884f9dc236f80edd8bfa961144c9e8d792eca722a7b32fc3d416d473ebc2c5fd4abfdad05d9184259b5bf8cd4d90fa0d31e2dec479e4f1a26066f2eea9a69236a3e52655c9e9aee691c8f3a26854308d5eaa3be85e0990703d73e56f");
+
+ printf("done.\n");
+ fflush(stdout);
+}
+
+/*
+ * AES known-answer tests. Order: key, plaintext, ciphertext.
+ */
+static const char *const KAT_AES[] = {
+ /*
+ * From FIPS-197.
+ */
+ "000102030405060708090a0b0c0d0e0f",
+ "00112233445566778899aabbccddeeff",
+ "69c4e0d86a7b0430d8cdb78070b4c55a",
+
+ "000102030405060708090a0b0c0d0e0f1011121314151617",
+ "00112233445566778899aabbccddeeff",
+ "dda97ca4864cdfe06eaf70a0ec0d7191",
+
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
+ "00112233445566778899aabbccddeeff",
+ "8ea2b7ca516745bfeafc49904b496089",
+
+ /*
+ * From NIST validation suite (ECBVarTxt128.rsp).
+ */
+ "00000000000000000000000000000000",
+ "80000000000000000000000000000000",
+ "3ad78e726c1ec02b7ebfe92b23d9ec34",
+
+ "00000000000000000000000000000000",
+ "c0000000000000000000000000000000",
+ "aae5939c8efdf2f04e60b9fe7117b2c2",
+
+ "00000000000000000000000000000000",
+ "e0000000000000000000000000000000",
+ "f031d4d74f5dcbf39daaf8ca3af6e527",
+
+ "00000000000000000000000000000000",
+ "f0000000000000000000000000000000",
+ "96d9fd5cc4f07441727df0f33e401a36",
+
+ "00000000000000000000000000000000",
+ "f8000000000000000000000000000000",
+ "30ccdb044646d7e1f3ccea3dca08b8c0",
+
+ "00000000000000000000000000000000",
+ "fc000000000000000000000000000000",
+ "16ae4ce5042a67ee8e177b7c587ecc82",
+
+ "00000000000000000000000000000000",
+ "fe000000000000000000000000000000",
+ "b6da0bb11a23855d9c5cb1b4c6412e0a",
+
+ "00000000000000000000000000000000",
+ "ff000000000000000000000000000000",
+ "db4f1aa530967d6732ce4715eb0ee24b",
+
+ "00000000000000000000000000000000",
+ "ff800000000000000000000000000000",
+ "a81738252621dd180a34f3455b4baa2f",
+
+ "00000000000000000000000000000000",
+ "ffc00000000000000000000000000000",
+ "77e2b508db7fd89234caf7939ee5621a",
+
+ "00000000000000000000000000000000",
+ "ffe00000000000000000000000000000",
+ "b8499c251f8442ee13f0933b688fcd19",
+
+ "00000000000000000000000000000000",
+ "fff00000000000000000000000000000",
+ "965135f8a81f25c9d630b17502f68e53",
+
+ "00000000000000000000000000000000",
+ "fff80000000000000000000000000000",
+ "8b87145a01ad1c6cede995ea3670454f",
+
+ "00000000000000000000000000000000",
+ "fffc0000000000000000000000000000",
+ "8eae3b10a0c8ca6d1d3b0fa61e56b0b2",
+
+ "00000000000000000000000000000000",
+ "fffe0000000000000000000000000000",
+ "64b4d629810fda6bafdf08f3b0d8d2c5",
+
+ "00000000000000000000000000000000",
+ "ffff0000000000000000000000000000",
+ "d7e5dbd3324595f8fdc7d7c571da6c2a",
+
+ "00000000000000000000000000000000",
+ "ffff8000000000000000000000000000",
+ "f3f72375264e167fca9de2c1527d9606",
+
+ "00000000000000000000000000000000",
+ "ffffc000000000000000000000000000",
+ "8ee79dd4f401ff9b7ea945d86666c13b",
+
+ "00000000000000000000000000000000",
+ "ffffe000000000000000000000000000",
+ "dd35cea2799940b40db3f819cb94c08b",
+
+ "00000000000000000000000000000000",
+ "fffff000000000000000000000000000",
+ "6941cb6b3e08c2b7afa581ebdd607b87",
+
+ "00000000000000000000000000000000",
+ "fffff800000000000000000000000000",
+ "2c20f439f6bb097b29b8bd6d99aad799",
+
+ "00000000000000000000000000000000",
+ "fffffc00000000000000000000000000",
+ "625d01f058e565f77ae86378bd2c49b3",
+
+ "00000000000000000000000000000000",
+ "fffffe00000000000000000000000000",
+ "c0b5fd98190ef45fbb4301438d095950",
+
+ "00000000000000000000000000000000",
+ "ffffff00000000000000000000000000",
+ "13001ff5d99806efd25da34f56be854b",
+
+ "00000000000000000000000000000000",
+ "ffffff80000000000000000000000000",
+ "3b594c60f5c8277a5113677f94208d82",
+
+ "00000000000000000000000000000000",
+ "ffffffc0000000000000000000000000",
+ "e9c0fc1818e4aa46bd2e39d638f89e05",
+
+ "00000000000000000000000000000000",
+ "ffffffe0000000000000000000000000",
+ "f8023ee9c3fdc45a019b4e985c7e1a54",
+
+ "00000000000000000000000000000000",
+ "fffffff0000000000000000000000000",
+ "35f40182ab4662f3023baec1ee796b57",
+
+ "00000000000000000000000000000000",
+ "fffffff8000000000000000000000000",
+ "3aebbad7303649b4194a6945c6cc3694",
+
+ "00000000000000000000000000000000",
+ "fffffffc000000000000000000000000",
+ "a2124bea53ec2834279bed7f7eb0f938",
+
+ "00000000000000000000000000000000",
+ "fffffffe000000000000000000000000",
+ "b9fb4399fa4facc7309e14ec98360b0a",
+
+ "00000000000000000000000000000000",
+ "ffffffff000000000000000000000000",
+ "c26277437420c5d634f715aea81a9132",
+
+ "00000000000000000000000000000000",
+ "ffffffff800000000000000000000000",
+ "171a0e1b2dd424f0e089af2c4c10f32f",
+
+ "00000000000000000000000000000000",
+ "ffffffffc00000000000000000000000",
+ "7cadbe402d1b208fe735edce00aee7ce",
+
+ "00000000000000000000000000000000",
+ "ffffffffe00000000000000000000000",
+ "43b02ff929a1485af6f5c6d6558baa0f",
+
+ "00000000000000000000000000000000",
+ "fffffffff00000000000000000000000",
+ "092faacc9bf43508bf8fa8613ca75dea",
+
+ "00000000000000000000000000000000",
+ "fffffffff80000000000000000000000",
+ "cb2bf8280f3f9742c7ed513fe802629c",
+
+ "00000000000000000000000000000000",
+ "fffffffffc0000000000000000000000",
+ "215a41ee442fa992a6e323986ded3f68",
+
+ "00000000000000000000000000000000",
+ "fffffffffe0000000000000000000000",
+ "f21e99cf4f0f77cea836e11a2fe75fb1",
+
+ "00000000000000000000000000000000",
+ "ffffffffff0000000000000000000000",
+ "95e3a0ca9079e646331df8b4e70d2cd6",
+
+ "00000000000000000000000000000000",
+ "ffffffffff8000000000000000000000",
+ "4afe7f120ce7613f74fc12a01a828073",
+
+ "00000000000000000000000000000000",
+ "ffffffffffc000000000000000000000",
+ "827f000e75e2c8b9d479beed913fe678",
+
+ "00000000000000000000000000000000",
+ "ffffffffffe000000000000000000000",
+ "35830c8e7aaefe2d30310ef381cbf691",
+
+ "00000000000000000000000000000000",
+ "fffffffffff000000000000000000000",
+ "191aa0f2c8570144f38657ea4085ebe5",
+
+ "00000000000000000000000000000000",
+ "fffffffffff800000000000000000000",
+ "85062c2c909f15d9269b6c18ce99c4f0",
+
+ "00000000000000000000000000000000",
+ "fffffffffffc00000000000000000000",
+ "678034dc9e41b5a560ed239eeab1bc78",
+
+ "00000000000000000000000000000000",
+ "fffffffffffe00000000000000000000",
+ "c2f93a4ce5ab6d5d56f1b93cf19911c1",
+
+ "00000000000000000000000000000000",
+ "ffffffffffff00000000000000000000",
+ "1c3112bcb0c1dcc749d799743691bf82",
+
+ "00000000000000000000000000000000",
+ "ffffffffffff80000000000000000000",
+ "00c55bd75c7f9c881989d3ec1911c0d4",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffc0000000000000000000",
+ "ea2e6b5ef182b7dff3629abd6a12045f",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffe0000000000000000000",
+ "22322327e01780b17397f24087f8cc6f",
+
+ "00000000000000000000000000000000",
+ "fffffffffffff0000000000000000000",
+ "c9cacb5cd11692c373b2411768149ee7",
+
+ "00000000000000000000000000000000",
+ "fffffffffffff8000000000000000000",
+ "a18e3dbbca577860dab6b80da3139256",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffc000000000000000000",
+ "79b61c37bf328ecca8d743265a3d425c",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffe000000000000000000",
+ "d2d99c6bcc1f06fda8e27e8ae3f1ccc7",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffff000000000000000000",
+ "1bfd4b91c701fd6b61b7f997829d663b",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffff800000000000000000",
+ "11005d52f25f16bdc9545a876a63490a",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffc00000000000000000",
+ "3a4d354f02bb5a5e47d39666867f246a",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffe00000000000000000",
+ "d451b8d6e1e1a0ebb155fbbf6e7b7dc3",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffff00000000000000000",
+ "6898d4f42fa7ba6a10ac05e87b9f2080",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffff80000000000000000",
+ "b611295e739ca7d9b50f8e4c0e754a3f",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffc0000000000000000",
+ "7d33fc7d8abe3ca1936759f8f5deaf20",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffe0000000000000000",
+ "3b5e0f566dc96c298f0c12637539b25c",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffff0000000000000000",
+ "f807c3e7985fe0f5a50e2cdb25c5109e",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffff8000000000000000",
+ "41f992a856fb278b389a62f5d274d7e9",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffc000000000000000",
+ "10d3ed7a6fe15ab4d91acbc7d0767ab1",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffe000000000000000",
+ "21feecd45b2e675973ac33bf0c5424fc",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffff000000000000000",
+ "1480cb3955ba62d09eea668f7c708817",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffff800000000000000",
+ "66404033d6b72b609354d5496e7eb511",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffc00000000000000",
+ "1c317a220a7d700da2b1e075b00266e1",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffe00000000000000",
+ "ab3b89542233f1271bf8fd0c0f403545",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffff00000000000000",
+ "d93eae966fac46dca927d6b114fa3f9e",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffff80000000000000",
+ "1bdec521316503d9d5ee65df3ea94ddf",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffc0000000000000",
+ "eef456431dea8b4acf83bdae3717f75f",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffe0000000000000",
+ "06f2519a2fafaa596bfef5cfa15c21b9",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffff0000000000000",
+ "251a7eac7e2fe809e4aa8d0d7012531a",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffff8000000000000",
+ "3bffc16e4c49b268a20f8d96a60b4058",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffc000000000000",
+ "e886f9281999c5bb3b3e8862e2f7c988",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffe000000000000",
+ "563bf90d61beef39f48dd625fcef1361",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffff000000000000",
+ "4d37c850644563c69fd0acd9a049325b",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffff800000000000",
+ "b87c921b91829ef3b13ca541ee1130a6",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffc00000000000",
+ "2e65eb6b6ea383e109accce8326b0393",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffe00000000000",
+ "9ca547f7439edc3e255c0f4d49aa8990",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffff00000000000",
+ "a5e652614c9300f37816b1f9fd0c87f9",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffff80000000000",
+ "14954f0b4697776f44494fe458d814ed",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffffc0000000000",
+ "7c8d9ab6c2761723fe42f8bb506cbcf7",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffffe0000000000",
+ "db7e1932679fdd99742aab04aa0d5a80",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffff0000000000",
+ "4c6a1c83e568cd10f27c2d73ded19c28",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffff8000000000",
+ "90ecbe6177e674c98de412413f7ac915",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffffc000000000",
+ "90684a2ac55fe1ec2b8ebd5622520b73",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffffe000000000",
+ "7472f9a7988607ca79707795991035e6",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffffff000000000",
+ "56aff089878bf3352f8df172a3ae47d8",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffffff800000000",
+ "65c0526cbe40161b8019a2a3171abd23",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffffffc00000000",
+ "377be0be33b4e3e310b4aabda173f84f",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffffffe00000000",
+ "9402e9aa6f69de6504da8d20c4fcaa2f",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffffff00000000",
+ "123c1f4af313ad8c2ce648b2e71fb6e1",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffffff80000000",
+ "1ffc626d30203dcdb0019fb80f726cf4",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffffffc0000000",
+ "76da1fbe3a50728c50fd2e621b5ad885",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffffffe0000000",
+ "082eb8be35f442fb52668e16a591d1d6",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffffffff0000000",
+ "e656f9ecf5fe27ec3e4a73d00c282fb3",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffffffff8000000",
+ "2ca8209d63274cd9a29bb74bcd77683a",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffffffffc000000",
+ "79bf5dce14bb7dd73a8e3611de7ce026",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffffffffe000000",
+ "3c849939a5d29399f344c4a0eca8a576",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffffffff000000",
+ "ed3c0a94d59bece98835da7aa4f07ca2",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffffffff800000",
+ "63919ed4ce10196438b6ad09d99cd795",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffffffffc00000",
+ "7678f3a833f19fea95f3c6029e2bc610",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffffffffe00000",
+ "3aa426831067d36b92be7c5f81c13c56",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffffffffff00000",
+ "9272e2d2cdd11050998c845077a30ea0",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffffffffff80000",
+ "088c4b53f5ec0ff814c19adae7f6246c",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffffffffffc0000",
+ "4010a5e401fdf0a0354ddbcc0d012b17",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffffffffffe0000",
+ "a87a385736c0a6189bd6589bd8445a93",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffffffffff0000",
+ "545f2b83d9616dccf60fa9830e9cd287",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffffffffff8000",
+ "4b706f7f92406352394037a6d4f4688d",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffffffffffc000",
+ "b7972b3941c44b90afa7b264bfba7387",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffffffffffe000",
+ "6f45732cf10881546f0fd23896d2bb60",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffffffffffff000",
+ "2e3579ca15af27f64b3c955a5bfc30ba",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffffffffffff800",
+ "34a2c5a91ae2aec99b7d1b5fa6780447",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffffffffffffc00",
+ "a4d6616bd04f87335b0e53351227a9ee",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffffffffffffe00",
+ "7f692b03945867d16179a8cefc83ea3f",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffffffffffff00",
+ "3bd141ee84a0e6414a26e7a4f281f8a2",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffffffffffff80",
+ "d1788f572d98b2b16ec5d5f3922b99bc",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffffffffffffc0",
+ "0833ff6f61d98a57b288e8c3586b85a6",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffffffffffffe0",
+ "8568261797de176bf0b43becc6285afb",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffffffffffffff0",
+ "f9b0fda0c4a898f5b9e6f661c4ce4d07",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffffffffffffff8",
+ "8ade895913685c67c5269f8aae42983e",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffffffffffffffc",
+ "39bde67d5c8ed8a8b1c37eb8fa9f5ac0",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffffffffffffffe",
+ "5c005e72c1418c44f569f2ea33ba54f3",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffffffffffffff",
+ "3f5b8cc9ea855a0afa7347d23e8d664e",
+
+ /*
+ * From NIST validation suite (ECBVarTxt192.rsp).
+ */
+ "000000000000000000000000000000000000000000000000",
+ "80000000000000000000000000000000",
+ "6cd02513e8d4dc986b4afe087a60bd0c",
+
+ "000000000000000000000000000000000000000000000000",
+ "c0000000000000000000000000000000",
+ "2ce1f8b7e30627c1c4519eada44bc436",
+
+ "000000000000000000000000000000000000000000000000",
+ "e0000000000000000000000000000000",
+ "9946b5f87af446f5796c1fee63a2da24",
+
+ "000000000000000000000000000000000000000000000000",
+ "f0000000000000000000000000000000",
+ "2a560364ce529efc21788779568d5555",
+
+ "000000000000000000000000000000000000000000000000",
+ "f8000000000000000000000000000000",
+ "35c1471837af446153bce55d5ba72a0a",
+
+ "000000000000000000000000000000000000000000000000",
+ "fc000000000000000000000000000000",
+ "ce60bc52386234f158f84341e534cd9e",
+
+ "000000000000000000000000000000000000000000000000",
+ "fe000000000000000000000000000000",
+ "8c7c27ff32bcf8dc2dc57c90c2903961",
+
+ "000000000000000000000000000000000000000000000000",
+ "ff000000000000000000000000000000",
+ "32bb6a7ec84499e166f936003d55a5bb",
+
+ "000000000000000000000000000000000000000000000000",
+ "ff800000000000000000000000000000",
+ "a5c772e5c62631ef660ee1d5877f6d1b",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffc00000000000000000000000000000",
+ "030d7e5b64f380a7e4ea5387b5cd7f49",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffe00000000000000000000000000000",
+ "0dc9a2610037009b698f11bb7e86c83e",
+
+ "000000000000000000000000000000000000000000000000",
+ "fff00000000000000000000000000000",
+ "0046612c766d1840c226364f1fa7ed72",
+
+ "000000000000000000000000000000000000000000000000",
+ "fff80000000000000000000000000000",
+ "4880c7e08f27befe78590743c05e698b",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffc0000000000000000000000000000",
+ "2520ce829a26577f0f4822c4ecc87401",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffe0000000000000000000000000000",
+ "8765e8acc169758319cb46dc7bcf3dca",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffff0000000000000000000000000000",
+ "e98f4ba4f073df4baa116d011dc24a28",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffff8000000000000000000000000000",
+ "f378f68c5dbf59e211b3a659a7317d94",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffc000000000000000000000000000",
+ "283d3b069d8eb9fb432d74b96ca762b4",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffe000000000000000000000000000",
+ "a7e1842e8a87861c221a500883245c51",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffff000000000000000000000000000",
+ "77aa270471881be070fb52c7067ce732",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffff800000000000000000000000000",
+ "01b0f476d484f43f1aeb6efa9361a8ac",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffc00000000000000000000000000",
+ "1c3a94f1c052c55c2d8359aff2163b4f",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffe00000000000000000000000000",
+ "e8a067b604d5373d8b0f2e05a03b341b",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffff00000000000000000000000000",
+ "a7876ec87f5a09bfea42c77da30fd50e",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffff80000000000000000000000000",
+ "0cf3e9d3a42be5b854ca65b13f35f48d",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffc0000000000000000000000000",
+ "6c62f6bbcab7c3e821c9290f08892dda",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffe0000000000000000000000000",
+ "7f5e05bd2068738196fee79ace7e3aec",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffff0000000000000000000000000",
+ "440e0d733255cda92fb46e842fe58054",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffff8000000000000000000000000",
+ "aa5d5b1c4ea1b7a22e5583ac2e9ed8a7",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffc000000000000000000000000",
+ "77e537e89e8491e8662aae3bc809421d",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffe000000000000000000000000",
+ "997dd3e9f1598bfa73f75973f7e93b76",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffff000000000000000000000000",
+ "1b38d4f7452afefcb7fc721244e4b72e",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffff800000000000000000000000",
+ "0be2b18252e774dda30cdda02c6906e3",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffc00000000000000000000000",
+ "d2695e59c20361d82652d7d58b6f11b2",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffe00000000000000000000000",
+ "902d88d13eae52089abd6143cfe394e9",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffff00000000000000000000000",
+ "d49bceb3b823fedd602c305345734bd2",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffff80000000000000000000000",
+ "707b1dbb0ffa40ef7d95def421233fae",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffc0000000000000000000000",
+ "7ca0c1d93356d9eb8aa952084d75f913",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffe0000000000000000000000",
+ "f2cbf9cb186e270dd7bdb0c28febc57d",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffff0000000000000000000000",
+ "c94337c37c4e790ab45780bd9c3674a0",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffff8000000000000000000000",
+ "8e3558c135252fb9c9f367ed609467a1",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffc000000000000000000000",
+ "1b72eeaee4899b443914e5b3a57fba92",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffe000000000000000000000",
+ "011865f91bc56868d051e52c9efd59b7",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffff000000000000000000000",
+ "e4771318ad7a63dd680f6e583b7747ea",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffff800000000000000000000",
+ "61e3d194088dc8d97e9e6db37457eac5",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffc00000000000000000000",
+ "36ff1ec9ccfbc349e5d356d063693ad6",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffe00000000000000000000",
+ "3cc9e9a9be8cc3f6fb2ea24088e9bb19",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffff00000000000000000000",
+ "1ee5ab003dc8722e74905d9a8fe3d350",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffff80000000000000000000",
+ "245339319584b0a412412869d6c2eada",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffc0000000000000000000",
+ "7bd496918115d14ed5380852716c8814",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffe0000000000000000000",
+ "273ab2f2b4a366a57d582a339313c8b1",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffff0000000000000000000",
+ "113365a9ffbe3b0ca61e98507554168b",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffff8000000000000000000",
+ "afa99c997ac478a0dea4119c9e45f8b1",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffc000000000000000000",
+ "9216309a7842430b83ffb98638011512",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffe000000000000000000",
+ "62abc792288258492a7cb45145f4b759",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffff000000000000000000",
+ "534923c169d504d7519c15d30e756c50",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffff800000000000000000",
+ "fa75e05bcdc7e00c273fa33f6ee441d2",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffc00000000000000000",
+ "7d350fa6057080f1086a56b17ec240db",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffe00000000000000000",
+ "f34e4a6324ea4a5c39a661c8fe5ada8f",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffff00000000000000000",
+ "0882a16f44088d42447a29ac090ec17e",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffff80000000000000000",
+ "3a3c15bfc11a9537c130687004e136ee",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffc0000000000000000",
+ "22c0a7678dc6d8cf5c8a6d5a9960767c",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffe0000000000000000",
+ "b46b09809d68b9a456432a79bdc2e38c",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffff0000000000000000",
+ "93baaffb35fbe739c17c6ac22eecf18f",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffff8000000000000000",
+ "c8aa80a7850675bc007c46df06b49868",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffc000000000000000",
+ "12c6f3877af421a918a84b775858021d",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffe000000000000000",
+ "33f123282c5d633924f7d5ba3f3cab11",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffff000000000000000",
+ "a8f161002733e93ca4527d22c1a0c5bb",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffff800000000000000",
+ "b72f70ebf3e3fda23f508eec76b42c02",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffc00000000000000",
+ "6a9d965e6274143f25afdcfc88ffd77c",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffe00000000000000",
+ "a0c74fd0b9361764ce91c5200b095357",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffff00000000000000",
+ "091d1fdc2bd2c346cd5046a8c6209146",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffff80000000000000",
+ "e2a37580116cfb71856254496ab0aca8",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffc0000000000000",
+ "e0b3a00785917c7efc9adba322813571",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffe0000000000000",
+ "733d41f4727b5ef0df4af4cf3cffa0cb",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffff0000000000000",
+ "a99ebb030260826f981ad3e64490aa4f",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffff8000000000000",
+ "73f34c7d3eae5e80082c1647524308ee",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffc000000000000",
+ "40ebd5ad082345b7a2097ccd3464da02",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffe000000000000",
+ "7cc4ae9a424b2cec90c97153c2457ec5",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffff000000000000",
+ "54d632d03aba0bd0f91877ebdd4d09cb",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffff800000000000",
+ "d3427be7e4d27cd54f5fe37b03cf0897",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffc00000000000",
+ "b2099795e88cc158fd75ea133d7e7fbe",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffe00000000000",
+ "a6cae46fb6fadfe7a2c302a34242817b",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffff00000000000",
+ "026a7024d6a902e0b3ffccbaa910cc3f",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffff80000000000",
+ "156f07767a85a4312321f63968338a01",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffc0000000000",
+ "15eec9ebf42b9ca76897d2cd6c5a12e2",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffe0000000000",
+ "db0d3a6fdcc13f915e2b302ceeb70fd8",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffff0000000000",
+ "71dbf37e87a2e34d15b20e8f10e48924",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffff8000000000",
+ "c745c451e96ff3c045e4367c833e3b54",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffc000000000",
+ "340da09c2dd11c3b679d08ccd27dd595",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffe000000000",
+ "8279f7c0c2a03ee660c6d392db025d18",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffff000000000",
+ "a4b2c7d8eba531ff47c5041a55fbd1ec",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffff800000000",
+ "74569a2ca5a7bd5131ce8dc7cbfbf72f",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffc00000000",
+ "3713da0c0219b63454035613b5a403dd",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffe00000000",
+ "8827551ddcc9df23fa72a3de4e9f0b07",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffff00000000",
+ "2e3febfd625bfcd0a2c06eb460da1732",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffff80000000",
+ "ee82e6ba488156f76496311da6941deb",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffc0000000",
+ "4770446f01d1f391256e85a1b30d89d3",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffe0000000",
+ "af04b68f104f21ef2afb4767cf74143c",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffff0000000",
+ "cf3579a9ba38c8e43653173e14f3a4c6",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffff8000000",
+ "b3bba904f4953e09b54800af2f62e7d4",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffc000000",
+ "fc4249656e14b29eb9c44829b4c59a46",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffe000000",
+ "9b31568febe81cfc2e65af1c86d1a308",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffff000000",
+ "9ca09c25f273a766db98a480ce8dfedc",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffff800000",
+ "b909925786f34c3c92d971883c9fbedf",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffffc00000",
+ "82647f1332fe570a9d4d92b2ee771d3b",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffffe00000",
+ "3604a7e80832b3a99954bca6f5b9f501",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffff00000",
+ "884607b128c5de3ab39a529a1ef51bef",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffff80000",
+ "670cfa093d1dbdb2317041404102435e",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffffc0000",
+ "7a867195f3ce8769cbd336502fbb5130",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffffe0000",
+ "52efcf64c72b2f7ca5b3c836b1078c15",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffffff0000",
+ "4019250f6eefb2ac5ccbcae044e75c7e",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffffff8000",
+ "022c4f6f5a017d292785627667ddef24",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffffffc000",
+ "e9c21078a2eb7e03250f71000fa9e3ed",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffffffe000",
+ "a13eaeeb9cd391da4e2b09490b3e7fad",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffffff000",
+ "c958a171dca1d4ed53e1af1d380803a9",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffffff800",
+ "21442e07a110667f2583eaeeee44dc8c",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffffffc00",
+ "59bbb353cf1dd867a6e33737af655e99",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffffffe00",
+ "43cd3b25375d0ce41087ff9fe2829639",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffffffff00",
+ "6b98b17e80d1118e3516bd768b285a84",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffffffff80",
+ "ae47ed3676ca0c08deea02d95b81db58",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffffffffc0",
+ "34ec40dc20413795ed53628ea748720b",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffffffffe0",
+ "4dc68163f8e9835473253542c8a65d46",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffffffff0",
+ "2aabb999f43693175af65c6c612c46fb",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffffffff8",
+ "e01f94499dac3547515c5b1d756f0f58",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffffffffc",
+ "9d12435a46480ce00ea349f71799df9a",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffffffffe",
+ "cef41d16d266bdfe46938ad7884cc0cf",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffffffffff",
+ "b13db4da1f718bc6904797c82bcf2d32",
+
+ /*
+ * From NIST validation suite (ECBVarTxt256.rsp).
+ */
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "80000000000000000000000000000000",
+ "ddc6bf790c15760d8d9aeb6f9a75fd4e",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "c0000000000000000000000000000000",
+ "0a6bdc6d4c1e6280301fd8e97ddbe601",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "e0000000000000000000000000000000",
+ "9b80eefb7ebe2d2b16247aa0efc72f5d",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "f0000000000000000000000000000000",
+ "7f2c5ece07a98d8bee13c51177395ff7",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "f8000000000000000000000000000000",
+ "7818d800dcf6f4be1e0e94f403d1e4c2",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fc000000000000000000000000000000",
+ "e74cd1c92f0919c35a0324123d6177d3",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fe000000000000000000000000000000",
+ "8092a4dcf2da7e77e93bdd371dfed82e",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ff000000000000000000000000000000",
+ "49af6b372135acef10132e548f217b17",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ff800000000000000000000000000000",
+ "8bcd40f94ebb63b9f7909676e667f1e7",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffc00000000000000000000000000000",
+ "fe1cffb83f45dcfb38b29be438dbd3ab",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffe00000000000000000000000000000",
+ "0dc58a8d886623705aec15cb1e70dc0e",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fff00000000000000000000000000000",
+ "c218faa16056bd0774c3e8d79c35a5e4",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fff80000000000000000000000000000",
+ "047bba83f7aa841731504e012208fc9e",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffc0000000000000000000000000000",
+ "dc8f0e4915fd81ba70a331310882f6da",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffe0000000000000000000000000000",
+ "1569859ea6b7206c30bf4fd0cbfac33c",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffff0000000000000000000000000000",
+ "300ade92f88f48fa2df730ec16ef44cd",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffff8000000000000000000000000000",
+ "1fe6cc3c05965dc08eb0590c95ac71d0",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffc000000000000000000000000000",
+ "59e858eaaa97fec38111275b6cf5abc0",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffe000000000000000000000000000",
+ "2239455e7afe3b0616100288cc5a723b",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffff000000000000000000000000000",
+ "3ee500c5c8d63479717163e55c5c4522",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffff800000000000000000000000000",
+ "d5e38bf15f16d90e3e214041d774daa8",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffc00000000000000000000000000",
+ "b1f4066e6f4f187dfe5f2ad1b17819d0",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffe00000000000000000000000000",
+ "6ef4cc4de49b11065d7af2909854794a",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffff00000000000000000000000000",
+ "ac86bc606b6640c309e782f232bf367f",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffff80000000000000000000000000",
+ "36aff0ef7bf3280772cf4cac80a0d2b2",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffc0000000000000000000000000",
+ "1f8eedea0f62a1406d58cfc3ecea72cf",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffe0000000000000000000000000",
+ "abf4154a3375a1d3e6b1d454438f95a6",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffff0000000000000000000000000",
+ "96f96e9d607f6615fc192061ee648b07",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffff8000000000000000000000000",
+ "cf37cdaaa0d2d536c71857634c792064",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffc000000000000000000000000",
+ "fbd6640c80245c2b805373f130703127",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffe000000000000000000000000",
+ "8d6a8afe55a6e481badae0d146f436db",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffff000000000000000000000000",
+ "6a4981f2915e3e68af6c22385dd06756",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffff800000000000000000000000",
+ "42a1136e5f8d8d21d3101998642d573b",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffc00000000000000000000000",
+ "9b471596dc69ae1586cee6158b0b0181",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffe00000000000000000000000",
+ "753665c4af1eff33aa8b628bf8741cfd",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffff00000000000000000000000",
+ "9a682acf40be01f5b2a4193c9a82404d",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffff80000000000000000000000",
+ "54fafe26e4287f17d1935f87eb9ade01",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffc0000000000000000000000",
+ "49d541b2e74cfe73e6a8e8225f7bd449",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffe0000000000000000000000",
+ "11a45530f624ff6f76a1b3826626ff7b",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffff0000000000000000000000",
+ "f96b0c4a8bc6c86130289f60b43b8fba",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffff8000000000000000000000",
+ "48c7d0e80834ebdc35b6735f76b46c8b",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffc000000000000000000000",
+ "2463531ab54d66955e73edc4cb8eaa45",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffe000000000000000000000",
+ "ac9bd8e2530469134b9d5b065d4f565b",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffff000000000000000000000",
+ "3f5f9106d0e52f973d4890e6f37e8a00",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffff800000000000000000000",
+ "20ebc86f1304d272e2e207e59db639f0",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffc00000000000000000000",
+ "e67ae6426bf9526c972cff072b52252c",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffe00000000000000000000",
+ "1a518dddaf9efa0d002cc58d107edfc8",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffff00000000000000000000",
+ "ead731af4d3a2fe3b34bed047942a49f",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffff80000000000000000000",
+ "b1d4efe40242f83e93b6c8d7efb5eae9",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffc0000000000000000000",
+ "cd2b1fec11fd906c5c7630099443610a",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffe0000000000000000000",
+ "a1853fe47fe29289d153161d06387d21",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffff0000000000000000000",
+ "4632154179a555c17ea604d0889fab14",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffff8000000000000000000",
+ "dd27cac6401a022e8f38f9f93e774417",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffc000000000000000000",
+ "c090313eb98674f35f3123385fb95d4d",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffe000000000000000000",
+ "cc3526262b92f02edce548f716b9f45c",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffff000000000000000000",
+ "c0838d1a2b16a7c7f0dfcc433c399c33",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffff800000000000000000",
+ "0d9ac756eb297695eed4d382eb126d26",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffc00000000000000000",
+ "56ede9dda3f6f141bff1757fa689c3e1",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffe00000000000000000",
+ "768f520efe0f23e61d3ec8ad9ce91774",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffff00000000000000000",
+ "b1144ddfa75755213390e7c596660490",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffff80000000000000000",
+ "1d7c0c4040b355b9d107a99325e3b050",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffc0000000000000000",
+ "d8e2bb1ae8ee3dcf5bf7d6c38da82a1a",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffe0000000000000000",
+ "faf82d178af25a9886a47e7f789b98d7",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffff0000000000000000",
+ "9b58dbfd77fe5aca9cfc190cd1b82d19",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffff8000000000000000",
+ "77f392089042e478ac16c0c86a0b5db5",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffc000000000000000",
+ "19f08e3420ee69b477ca1420281c4782",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffe000000000000000",
+ "a1b19beee4e117139f74b3c53fdcb875",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffff000000000000000",
+ "a37a5869b218a9f3a0868d19aea0ad6a",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffff800000000000000",
+ "bc3594e865bcd0261b13202731f33580",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffc00000000000000",
+ "811441ce1d309eee7185e8c752c07557",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffe00000000000000",
+ "959971ce4134190563518e700b9874d1",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffff00000000000000",
+ "76b5614a042707c98e2132e2e805fe63",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffff80000000000000",
+ "7d9fa6a57530d0f036fec31c230b0cc6",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffc0000000000000",
+ "964153a83bf6989a4ba80daa91c3e081",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffe0000000000000",
+ "a013014d4ce8054cf2591d06f6f2f176",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffff0000000000000",
+ "d1c5f6399bf382502e385eee1474a869",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffff8000000000000",
+ "0007e20b8298ec354f0f5fe7470f36bd",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffc000000000000",
+ "b95ba05b332da61ef63a2b31fcad9879",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffe000000000000",
+ "4620a49bd967491561669ab25dce45f4",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffff000000000000",
+ "12e71214ae8e04f0bb63d7425c6f14d5",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffff800000000000",
+ "4cc42fc1407b008fe350907c092e80ac",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffc00000000000",
+ "08b244ce7cbc8ee97fbba808cb146fda",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffe00000000000",
+ "39b333e8694f21546ad1edd9d87ed95b",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffff00000000000",
+ "3b271f8ab2e6e4a20ba8090f43ba78f3",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffff80000000000",
+ "9ad983f3bf651cd0393f0a73cccdea50",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffc0000000000",
+ "8f476cbff75c1f725ce18e4bbcd19b32",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffe0000000000",
+ "905b6267f1d6ab5320835a133f096f2a",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffff0000000000",
+ "145b60d6d0193c23f4221848a892d61a",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffff8000000000",
+ "55cfb3fb6d75cad0445bbc8dafa25b0f",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffc000000000",
+ "7b8e7098e357ef71237d46d8b075b0f5",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffe000000000",
+ "2bf27229901eb40f2df9d8398d1505ae",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffff000000000",
+ "83a63402a77f9ad5c1e931a931ecd706",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffff800000000",
+ "6f8ba6521152d31f2bada1843e26b973",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffc00000000",
+ "e5c3b8e30fd2d8e6239b17b44bd23bbd",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffe00000000",
+ "1ac1f7102c59933e8b2ddc3f14e94baa",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffff00000000",
+ "21d9ba49f276b45f11af8fc71a088e3d",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffff80000000",
+ "649f1cddc3792b4638635a392bc9bade",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffc0000000",
+ "e2775e4b59c1bc2e31a2078c11b5a08c",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffe0000000",
+ "2be1fae5048a25582a679ca10905eb80",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffff0000000",
+ "da86f292c6f41ea34fb2068df75ecc29",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffff8000000",
+ "220df19f85d69b1b562fa69a3c5beca5",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffc000000",
+ "1f11d5d0355e0b556ccdb6c7f5083b4d",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffe000000",
+ "62526b78be79cb384633c91f83b4151b",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffff000000",
+ "90ddbcb950843592dd47bbef00fdc876",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffff800000",
+ "2fd0e41c5b8402277354a7391d2618e2",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffffc00000",
+ "3cdf13e72dee4c581bafec70b85f9660",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffffe00000",
+ "afa2ffc137577092e2b654fa199d2c43",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffff00000",
+ "8d683ee63e60d208e343ce48dbc44cac",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffff80000",
+ "705a4ef8ba2133729c20185c3d3a4763",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffffc0000",
+ "0861a861c3db4e94194211b77ed761b9",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffffe0000",
+ "4b00c27e8b26da7eab9d3a88dec8b031",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffffff0000",
+ "5f397bf03084820cc8810d52e5b666e9",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffffff8000",
+ "63fafabb72c07bfbd3ddc9b1203104b8",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffffffc000",
+ "683e2140585b18452dd4ffbb93c95df9",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffffffe000",
+ "286894e48e537f8763b56707d7d155c8",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffffff000",
+ "a423deabc173dcf7e2c4c53e77d37cd1",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffffff800",
+ "eb8168313e1cfdfdb5e986d5429cf172",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffffffc00",
+ "27127daafc9accd2fb334ec3eba52323",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffffffe00",
+ "ee0715b96f72e3f7a22a5064fc592f4c",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffffffff00",
+ "29ee526770f2a11dcfa989d1ce88830f",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffffffff80",
+ "0493370e054b09871130fe49af730a5a",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffffffffc0",
+ "9b7b940f6c509f9e44a4ee140448ee46",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffffffffe0",
+ "2915be4a1ecfdcbe3e023811a12bb6c7",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffffffff0",
+ "7240e524bc51d8c4d440b1be55d1062c",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffffffff8",
+ "da63039d38cb4612b2dc36ba26684b93",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffffffffc",
+ "0f59cb5a4b522e2ac56c1a64f558ad9a",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffffffffe",
+ "7bfe9d876c6d63c1d035da8fe21c409d",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffffffffff",
+ "acdace8078a32b1a182bfa4987ca1347",
+
+ /*
+ * Table end marker.
+ */
+ NULL
+};
+
+/*
+ * AES known-answer tests for CBC. Order: key, IV, plaintext, ciphertext.
+ */
+static const char *const KAT_AES_CBC[] = {
+ /*
+ * From NIST validation suite "Multiblock Message Test"
+ * (cbcmmt128.rsp).
+ */
+ "1f8e4973953f3fb0bd6b16662e9a3c17",
+ "2fe2b333ceda8f98f4a99b40d2cd34a8",
+ "45cf12964fc824ab76616ae2f4bf0822",
+ "0f61c4d44c5147c03c195ad7e2cc12b2",
+
+ "0700d603a1c514e46b6191ba430a3a0c",
+ "aad1583cd91365e3bb2f0c3430d065bb",
+ "068b25c7bfb1f8bdd4cfc908f69dffc5ddc726a197f0e5f720f730393279be91",
+ "c4dc61d9725967a3020104a9738f23868527ce839aab1752fd8bdb95a82c4d00",
+
+ "3348aa51e9a45c2dbe33ccc47f96e8de",
+ "19153c673160df2b1d38c28060e59b96",
+ "9b7cee827a26575afdbb7c7a329f887238052e3601a7917456ba61251c214763d5e1847a6ad5d54127a399ab07ee3599",
+ "d5aed6c9622ec451a15db12819952b6752501cf05cdbf8cda34a457726ded97818e1f127a28d72db5652749f0c6afee5",
+
+ "b7f3c9576e12dd0db63e8f8fac2b9a39",
+ "c80f095d8bb1a060699f7c19974a1aa0",
+ "9ac19954ce1319b354d3220460f71c1e373f1cd336240881160cfde46ebfed2e791e8d5a1a136ebd1dc469dec00c4187722b841cdabcb22c1be8a14657da200e",
+ "19b9609772c63f338608bf6eb52ca10be65097f89c1e0905c42401fd47791ae2c5440b2d473116ca78bd9ff2fb6015cfd316524eae7dcb95ae738ebeae84a467",
+
+ "b6f9afbfe5a1562bba1368fc72ac9d9c",
+ "3f9d5ebe250ee7ce384b0d00ee849322",
+ "db397ec22718dbffb9c9d13de0efcd4611bf792be4fce0dc5f25d4f577ed8cdbd4eb9208d593dda3d4653954ab64f05676caa3ce9bfa795b08b67ceebc923fdc89a8c431188e9e482d8553982cf304d1",
+ "10ea27b19e16b93af169c4a88e06e35c99d8b420980b058e34b4b8f132b13766f72728202b089f428fecdb41c79f8aa0d0ef68f5786481cca29e2126f69bc14160f1ae2187878ba5c49cf3961e1b7ee9",
+
+ "bbe7b7ba07124ff1ae7c3416fe8b465e",
+ "7f65b5ee3630bed6b84202d97fb97a1e",
+ "2aad0c2c4306568bad7447460fd3dac054346d26feddbc9abd9110914011b4794be2a9a00a519a51a5b5124014f4ed2735480db21b434e99a911bb0b60fe0253763725b628d5739a5117b7ee3aefafc5b4c1bf446467e7bf5f78f31ff7caf187",
+ "3b8611bfc4973c5cd8e982b073b33184cd26110159172e44988eb5ff5661a1e16fad67258fcbfee55469267a12dc374893b4e3533d36f5634c3095583596f135aa8cd1138dc898bc5651ee35a92ebf89ab6aeb5366653bc60a70e0074fc11efe",
+
+ "89a553730433f7e6d67d16d373bd5360",
+ "f724558db3433a523f4e51a5bea70497",
+ "807bc4ea684eedcfdcca30180680b0f1ae2814f35f36d053c5aea6595a386c1442770f4d7297d8b91825ee7237241da8925dd594ccf676aecd46ca2068e8d37a3a0ec8a7d5185a201e663b5ff36ae197110188a23503763b8218826d23ced74b31e9f6e2d7fbfa6cb43420c7807a8625",
+ "406af1429a478c3d07e555c5287a60500d37fc39b68e5bbb9bafd6ddb223828561d6171a308d5b1a4551e8a5e7d572918d25c968d3871848d2f16635caa9847f38590b1df58ab5efb985f2c66cfaf86f61b3f9c0afad6c963c49cee9b8bc81a2ddb06c967f325515a4849eec37ce721a",
+
+ "c491ca31f91708458e29a925ec558d78",
+ "9ef934946e5cd0ae97bd58532cb49381",
+ "cb6a787e0dec56f9a165957f81af336ca6b40785d9e94093c6190e5152649f882e874d79ac5e167bd2a74ce5ae088d2ee854f6539e0a94796b1e1bd4c9fcdbc79acbef4d01eeb89776d18af71ae2a4fc47dd66df6c4dbe1d1850e466549a47b636bcc7c2b3a62495b56bb67b6d455f1eebd9bfefecbca6c7f335cfce9b45cb9d",
+ "7b2931f5855f717145e00f152a9f4794359b1ffcb3e55f594e33098b51c23a6c74a06c1d94fded7fd2ae42c7db7acaef5844cb33aeddc6852585ed0020a6699d2cb53809cefd169148ce42292afab063443978306c582c18b9ce0da3d084ce4d3c482cfd8fcf1a85084e89fb88b40a084d5e972466d07666126fb761f84078f2",
+
+ "f6e87d71b0104d6eb06a68dc6a71f498",
+ "1c245f26195b76ebebc2edcac412a2f8",
+ "f82bef3c73a6f7f80db285726d691db6bf55eec25a859d3ba0e0445f26b9bb3b16a3161ed1866e4dd8f2e5f8ecb4e46d74a7a78c20cdfc7bcc9e479ba7a0caba9438238ad0c01651d5d98de37f03ddce6e6b4bd4ab03cf9e8ed818aedfa1cf963b932067b97d776dce1087196e7e913f7448e38244509f0caf36bd8217e15336d35c149fd4e41707893fdb84014f8729",
+ "b09512f3eff9ed0d85890983a73dadbb7c3678d52581be64a8a8fc586f490f2521297a478a0598040ebd0f5509fafb0969f9d9e600eaef33b1b93eed99687b167f89a5065aac439ce46f3b8d22d30865e64e45ef8cd30b6984353a844a11c8cd60dba0e8866b3ee30d24b3fa8a643b328353e06010fa8273c8fd54ef0a2b6930e5520aae5cd5902f9b86a33592ca4365",
+
+ "2c14413751c31e2730570ba3361c786b",
+ "1dbbeb2f19abb448af849796244a19d7",
+ "40d930f9a05334d9816fe204999c3f82a03f6a0457a8c475c94553d1d116693adc618049f0a769a2eed6a6cb14c0143ec5cccdbc8dec4ce560cfd206225709326d4de7948e54d603d01b12d7fed752fb23f1aa4494fbb00130e9ded4e77e37c079042d828040c325b1a5efd15fc842e44014ca4374bf38f3c3fc3ee327733b0c8aee1abcd055772f18dc04603f7b2c1ea69ff662361f2be0a171bbdcea1e5d3f",
+ "6be8a12800455a320538853e0cba31bd2d80ea0c85164a4c5c261ae485417d93effe2ebc0d0a0b51d6ea18633d210cf63c0c4ddbc27607f2e81ed9113191ef86d56f3b99be6c415a4150299fb846ce7160b40b63baf1179d19275a2e83698376d28b92548c68e06e6d994e2c1501ed297014e702cdefee2f656447706009614d801de1caaf73f8b7fa56cf1ba94b631933bbe577624380850f117435a0355b2b",
+
+ /*
+ * From NIST validation suite "Multiblock Message Test"
+ * (cbcmmt192.rsp).
+ */
+ "ba75f4d1d9d7cf7f551445d56cc1a8ab2a078e15e049dc2c",
+ "531ce78176401666aa30db94ec4a30eb",
+ "c51fc276774dad94bcdc1d2891ec8668",
+ "70dd95a14ee975e239df36ff4aee1d5d",
+
+ "eab3b19c581aa873e1981c83ab8d83bbf8025111fb2e6b21",
+ "f3d6667e8d4d791e60f7505ba383eb05",
+ "9d4e4cccd1682321856df069e3f1c6fa391a083a9fb02d59db74c14081b3acc4",
+ "51d44779f90d40a80048276c035cb49ca2a47bcb9b9cf7270b9144793787d53f",
+
+ "16c93bb398f1fc0cf6d68fc7a5673cdf431fa147852b4a2d",
+ "eaaeca2e07ddedf562f94df63f0a650f",
+ "c5ce958613bf741718c17444484ebaf1050ddcacb59b9590178cbe69d7ad7919608cb03af13bbe04f3506b718a301ea0",
+ "ed6a50e0c6921d52d6647f75d67b4fd56ace1fedb8b5a6a997b4d131640547d22c5d884a75e6752b5846b5b33a5181f4",
+
+ "067bb17b4df785697eaccf961f98e212cb75e6797ce935cb",
+ "8b59c9209c529ca8391c9fc0ce033c38",
+ "db3785a889b4bd387754da222f0e4c2d2bfe0d79e05bc910fba941beea30f1239eacf0068f4619ec01c368e986fca6b7c58e490579d29611bd10087986eff54f",
+ "d5f5589760bf9c762228fde236de1fa2dd2dad448db3fa9be0c4196efd46a35c84dd1ac77d9db58c95918cb317a6430a08d2fb6a8e8b0f1c9b72c7a344dc349f",
+
+ "0fd39de83e0be77a79c8a4a612e3dd9c8aae2ce35e7a2bf8",
+ "7e1d629b84f93b079be51f9a5f5cb23c",
+ "38fbda37e28fa86d9d83a4345e419dea95d28c7818ff25925db6ac3aedaf0a86154e20a4dfcc5b1b4192895393e5eb5846c88bdbd41ecf7af3104f410eaee470f5d9017ed460475f626953035a13db1f",
+ "edadae2f9a45ff3473e02d904c94d94a30a4d92da4deb6bcb4b0774472694571842039f21c496ef93fd658842c735f8a81fcd0aa578442ab893b18f606aed1bab11f81452dd45e9b56adf2eccf4ea095",
+
+ "e3fecc75f0075a09b383dfd389a3d33cc9b854b3b254c0f4",
+ "36eab883afef936cc38f63284619cd19",
+ "931b2f5f3a5820d53a6beaaa6431083a3488f4eb03b0f5b57ef838e1579623103bd6e6800377538b2e51ef708f3c4956432e8a8ee6a34e190642b26ad8bdae6c2af9a6c7996f3b6004d2671e41f1c9f40ee03d1c4a52b0a0654a331f15f34dce",
+ "75395974bd32b3665654a6c8e396b88ae34b123575872a7ab687d8e76b46df911a8a590cd01d2f5c330be3a6626e9dd3aa5e10ed14e8ff829811b6fed50f3f533ca4385a1cbca78f5c4744e50f2f8359165c2485d1324e76c3eae76a0ccac629",
+
+ "f9c27565eb07947c8cb51b79248430f7b1066c3d2fdc3d13",
+ "2bd67cc89ab7948d644a49672843cbd9",
+ "6abcc270173cf114d44847e911a050db57ba7a2e2c161c6f37ccb6aaa4677bddcaf50cad0b5f8758fcf7c0ebc650ceb5cd52cafb8f8dd3edcece55d9f1f08b9fa8f54365cf56e28b9596a7e1dd1d3418e4444a7724add4cf79d527b183ec88de4be4eeff29c80a97e54f85351cb189ee",
+ "ca282924a61187feb40520979106e5cc861957f23828dcb7285e0eaac8a0ca2a6b60503d63d6039f4693dba32fa1f73ae2e709ca94911f28a5edd1f30eaddd54680c43acc9c74cd90d8bb648b4e544275f47e514daa20697f66c738eb30337f017fca1a26da4d1a0cc0a0e98e2463070",
+
+ "fb09cf9e00dbf883689d079c920077c0073c31890b55bab5",
+ "e3c89bd097c3abddf64f4881db6dbfe2",
+ "c1a37683fb289467dd1b2c89efba16bbd2ee24cf18d19d44596ded2682c79a2f711c7a32bf6a24badd32a4ee637c73b7a41da6258635650f91fb9ffa45bdfc3cb122136241b3deced8996aa51ea8d3e81c9d70e006a44bc0571ed48623a0d622a93fa9da290baaedf5d9e876c94620945ff8ecc83f27379ed55cf490c5790f27",
+ "8158e21420f25b59d6ae943fa1cbf21f02e979f419dab0126a721b7eef55bee9ad97f5ccff7d239057bbc19a8c378142f7672f1d5e7e17d7bebcb0070e8355cace6660171a53b61816ae824a6ef69ce470b6ffd3b5bb4b438874d91d27854d3b6f25860d3868958de3307d62b1339bdddb8a318c0ce0f33c17caf0e9f6040820",
+
+ "bca6fa3c67fd294e958f66fe8bd64f45f428f5bc8e9733a7",
+ "92a47f2833f1450d1da41717bdc6e83c",
+ "5becbc31d8bead6d36ae014a5863d14a431e6b55d29ea6baaa417271716db3a33b2e506b452086dfe690834ac2de30bc41254ec5401ec47d064237c7792fdcd7914d8af20eb114756642d519021a8c75a92f6bc53d326ae9a5b7e1b10a9756574692934d9939fc399e0c203f7edf8e7e6482eadd31a0400770e897b48c6bca2b404593045080e93377358c42a0f4dede",
+ "926db248cc1ba20f0c57631a7c8aef094f791937b905949e3460240e8bfa6fa483115a1b310b6e4369caebc5262888377b1ddaa5800ea496a2bdff0f9a1031e7129c9a20e35621e7f0b8baca0d87030f2ae7ca8593c8599677a06fd4b26009ead08fecac24caa9cf2cad3b470c8227415a7b1e0f2eab3fad96d70a209c8bb26c627677e2531b9435ca6e3c444d195b5f",
+
+ "162ad50ee64a0702aa551f571dedc16b2c1b6a1e4d4b5eee",
+ "24408038161a2ccae07b029bb66355c1",
+ "be8abf00901363987a82cc77d0ec91697ba3857f9e4f84bd79406c138d02698f003276d0449120bef4578d78fecabe8e070e11710b3f0a2744bd52434ec70015884c181ebdfd51c604a71c52e4c0e110bc408cd462b248a80b8a8ac06bb952ac1d7faed144807f1a731b7febcaf7835762defe92eccfc7a9944e1c702cffe6bc86733ed321423121085ac02df8962bcbc1937092eebf0e90a8b20e3dd8c244ae",
+ "c82cf2c476dea8cb6a6e607a40d2f0391be82ea9ec84a537a6820f9afb997b76397d005424faa6a74dc4e8c7aa4a8900690f894b6d1dca80675393d2243adac762f159301e357e98b724762310cd5a7bafe1c2a030dba46fd93a9fdb89cc132ca9c17dc72031ec6822ee5a9d99dbca66c784c01b0885cbb62e29d97801927ec415a5d215158d325f9ee689437ad1b7684ad33c0d92739451ac87f39ff8c31b84",
+
+ /*
+ * From NIST validation suite "Multiblock Message Test"
+ * (cbcmmt256.rsp).
+ */
+ "6ed76d2d97c69fd1339589523931f2a6cff554b15f738f21ec72dd97a7330907",
+ "851e8764776e6796aab722dbb644ace8",
+ "6282b8c05c5c1530b97d4816ca434762",
+ "6acc04142e100a65f51b97adf5172c41",
+
+ "dce26c6b4cfb286510da4eecd2cffe6cdf430f33db9b5f77b460679bd49d13ae",
+ "fdeaa134c8d7379d457175fd1a57d3fc",
+ "50e9eee1ac528009e8cbcd356975881f957254b13f91d7c6662d10312052eb00",
+ "2fa0df722a9fd3b64cb18fb2b3db55ff2267422757289413f8f657507412a64c",
+
+ "fe8901fecd3ccd2ec5fdc7c7a0b50519c245b42d611a5ef9e90268d59f3edf33",
+ "bd416cb3b9892228d8f1df575692e4d0",
+ "8d3aa196ec3d7c9b5bb122e7fe77fb1295a6da75abe5d3a510194d3a8a4157d5c89d40619716619859da3ec9b247ced9",
+ "608e82c7ab04007adb22e389a44797fed7de090c8c03ca8a2c5acd9e84df37fbc58ce8edb293e98f02b640d6d1d72464",
+
+ "0493ff637108af6a5b8e90ac1fdf035a3d4bafd1afb573be7ade9e8682e663e5",
+ "c0cd2bebccbb6c49920bd5482ac756e8",
+ "8b37f9148df4bb25956be6310c73c8dc58ea9714ff49b643107b34c9bff096a94fedd6823526abc27a8e0b16616eee254ab4567dd68e8ccd4c38ac563b13639c",
+ "05d5c77729421b08b737e41119fa4438d1f570cc772a4d6c3df7ffeda0384ef84288ce37fc4c4c7d1125a499b051364c389fd639bdda647daa3bdadab2eb5594",
+
+ "9adc8fbd506e032af7fa20cf5343719de6d1288c158c63d6878aaf64ce26ca85",
+ "11958dc6ab81e1c7f01631e9944e620f",
+ "c7917f84f747cd8c4b4fedc2219bdbc5f4d07588389d8248854cf2c2f89667a2d7bcf53e73d32684535f42318e24cd45793950b3825e5d5c5c8fcd3e5dda4ce9246d18337ef3052d8b21c5561c8b660e",
+ "9c99e68236bb2e929db1089c7750f1b356d39ab9d0c40c3e2f05108ae9d0c30b04832ccdbdc08ebfa426b7f5efde986ed05784ce368193bb3699bc691065ac62e258b9aa4cc557e2b45b49ce05511e65",
+
+ "73b8faf00b3302ac99855cf6f9e9e48518690a5906a4869d4dcf48d282faae2a",
+ "b3cb97a80a539912b8c21f450d3b9395",
+ "3adea6e06e42c4f041021491f2775ef6378cb08824165edc4f6448e232175b60d0345b9f9c78df6596ec9d22b7b9e76e8f3c76b32d5d67273f1d83fe7a6fc3dd3c49139170fa5701b3beac61b490f0a9e13f844640c4500f9ad3087adfb0ae10",
+ "ac3d6dbafe2e0f740632fd9e820bf6044cd5b1551cbb9cc03c0b25c39ccb7f33b83aacfca40a3265f2bbff879153448acacb88fcfb3bb7b10fe463a68c0109f028382e3e557b1adf02ed648ab6bb895df0205d26ebbfa9a5fd8cebd8e4bee3dc",
+
+ "9ddf3745896504ff360a51a3eb49c01b79fccebc71c3abcb94a949408b05b2c9",
+ "e79026639d4aa230b5ccffb0b29d79bc",
+ "cf52e5c3954c51b94c9e38acb8c9a7c76aebdaa9943eae0a1ce155a2efdb4d46985d935511471452d9ee64d2461cb2991d59fc0060697f9a671672163230f367fed1422316e52d29eceacb8768f56d9b80f6d278093c9a8acd3cfd7edd8ebd5c293859f64d2f8486ae1bd593c65bc014",
+ "34df561bd2cfebbcb7af3b4b8d21ca5258312e7e2e4e538e35ad2490b6112f0d7f148f6aa8d522a7f3c61d785bd667db0e1dc4606c318ea4f26af4fe7d11d4dcff0456511b4aed1a0d91ba4a1fd6cd9029187bc5881a5a07fe02049d39368e83139b12825bae2c7be81e6f12c61bb5c5",
+
+ "458b67bf212d20f3a57fce392065582dcefbf381aa22949f8338ab9052260e1d",
+ "4c12effc5963d40459602675153e9649",
+ "256fd73ce35ae3ea9c25dd2a9454493e96d8633fe633b56176dce8785ce5dbbb84dbf2c8a2eeb1e96b51899605e4f13bbc11b93bf6f39b3469be14858b5b720d4a522d36feed7a329c9b1e852c9280c47db8039c17c4921571a07d1864128330e09c308ddea1694e95c84500f1a61e614197e86a30ecc28df64ccb3ccf5437aa",
+ "90b7b9630a2378f53f501ab7beff039155008071bc8438e789932cfd3eb1299195465e6633849463fdb44375278e2fdb1310821e6492cf80ff15cb772509fb426f3aeee27bd4938882fd2ae6b5bd9d91fa4a43b17bb439ebbe59c042310163a82a5fe5388796eee35a181a1271f00be29b852d8fa759bad01ff4678f010594cd",
+
+ "d2412db0845d84e5732b8bbd642957473b81fb99ca8bff70e7920d16c1dbec89",
+ "51c619fcf0b23f0c7925f400a6cacb6d",
+ "026006c4a71a180c9929824d9d095b8faaa86fc4fa25ecac61d85ff6de92dfa8702688c02a282c1b8af4449707f22d75e91991015db22374c95f8f195d5bb0afeb03040ff8965e0e1339dba5653e174f8aa5a1b39fe3ac839ce307a4e44b4f8f1b0063f738ec18acdbff2ebfe07383e734558723e741f0a1836dafdf9de82210a9248bc113b3c1bc8b4e252ca01bd803",
+ "0254b23463bcabec5a395eb74c8fb0eb137a07bc6f5e9f61ec0b057de305714f8fa294221c91a159c315939b81e300ee902192ec5f15254428d8772f79324ec43298ca21c00b370273ee5e5ed90e43efa1e05a5d171209fe34f9f29237dba2a6726650fd3b1321747d1208863c6c3c6b3e2d879ab5f25782f08ba8f2abbe63e0bedb4a227e81afb36bb6645508356d34",
+
+ "48be597e632c16772324c8d3fa1d9c5a9ecd010f14ec5d110d3bfec376c5532b",
+ "d6d581b8cf04ebd3b6eaa1b53f047ee1",
+ "0c63d413d3864570e70bb6618bf8a4b9585586688c32bba0a5ecc1362fada74ada32c52acfd1aa7444ba567b4e7daaecf7cc1cb29182af164ae5232b002868695635599807a9a7f07a1f137e97b1e1c9dabc89b6a5e4afa9db5855edaa575056a8f4f8242216242bb0c256310d9d329826ac353d715fa39f80cec144d6424558f9f70b98c920096e0f2c855d594885a00625880e9dfb734163cecef72cf030b8",
+ "fc5873e50de8faf4c6b84ba707b0854e9db9ab2e9f7d707fbba338c6843a18fc6facebaf663d26296fb329b4d26f18494c79e09e779647f9bafa87489630d79f4301610c2300c19dbf3148b7cac8c4f4944102754f332e92b6f7c5e75bc6179eb877a078d4719009021744c14f13fd2a55a2b9c44d18000685a845a4f632c7c56a77306efa66a24d05d088dcd7c13fe24fc447275965db9e4d37fbc9304448cd",
+
+ /*
+ * End-of-table marker.
+ */
+ NULL
+};
+
+/*
+ * AES known-answer tests for CTR. Order: key, IV, plaintext, ciphertext.
+ */
+static const char *const KAT_AES_CTR[] = {
+ /*
+ * From RFC 3686.
+ */
+ "ae6852f8121067cc4bf7a5765577f39e",
+ "000000300000000000000000",
+ "53696e676c6520626c6f636b206d7367",
+ "e4095d4fb7a7b3792d6175a3261311b8",
+
+ "7e24067817fae0d743d6ce1f32539163",
+ "006cb6dbc0543b59da48d90b",
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
+ "5104a106168a72d9790d41ee8edad388eb2e1efc46da57c8fce630df9141be28",
+
+ "7691be035e5020a8ac6e618529f9a0dc",
+ "00e0017b27777f3f4a1786f0",
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223",
+ "c1cf48a89f2ffdd9cf4652e9efdb72d74540a42bde6d7836d59a5ceaaef3105325b2072f",
+
+ "16af5b145fc9f579c175f93e3bfb0eed863d06ccfdb78515",
+ "0000004836733c147d6d93cb",
+ "53696e676c6520626c6f636b206d7367",
+ "4b55384fe259c9c84e7935a003cbe928",
+
+ "7c5cb2401b3dc33c19e7340819e0f69c678c3db8e6f6a91a",
+ "0096b03b020c6eadc2cb500d",
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
+ "453243fc609b23327edfaafa7131cd9f8490701c5ad4a79cfc1fe0ff42f4fb00",
+
+ "02bf391ee8ecb159b959617b0965279bf59b60a786d3e0fe",
+ "0007bdfd5cbd60278dcc0912",
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223",
+ "96893fc55e5c722f540b7dd1ddf7e758d288bc95c69165884536c811662f2188abee0935",
+
+ "776beff2851db06f4c8a0542c8696f6c6a81af1eec96b4d37fc1d689e6c1c104",
+ "00000060db5672c97aa8f0b2",
+ "53696e676c6520626c6f636b206d7367",
+ "145ad01dbf824ec7560863dc71e3e0c0",
+
+ "f6d66d6bd52d59bb0796365879eff886c66dd51a5b6a99744b50590c87a23884",
+ "00faac24c1585ef15a43d875",
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
+ "f05e231b3894612c49ee000b804eb2a9b8306b508f839d6a5530831d9344af1c",
+
+ "ff7a617ce69148e4f1726e2f43581de2aa62d9f805532edff1eed687fb54153d",
+ "001cc5b751a51d70a1c11148",
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223",
+ "eb6c52821d0bbbf7ce7594462aca4faab407df866569fd07f48cc0b583d6071f1ec0e6b8",
+
+ /*
+ * End-of-table marker.
+ */
+ NULL
+};
+
+static void
+monte_carlo_AES_encrypt(const br_block_cbcenc_class *ve,
+ char *skey, char *splain, char *scipher)
+{
+ unsigned char key[32];
+ unsigned char buf[16];
+ unsigned char pbuf[16];
+ unsigned char cipher[16];
+ size_t key_len;
+ int i, j, k;
+ br_aes_gen_cbcenc_keys v_ec;
+ const br_block_cbcenc_class **ec;
+
+ ec = &v_ec.vtable;
+ key_len = hextobin(key, skey);
+ hextobin(buf, splain);
+ hextobin(cipher, scipher);
+ for (i = 0; i < 100; i ++) {
+ ve->init(ec, key, key_len);
+ for (j = 0; j < 1000; j ++) {
+ unsigned char iv[16];
+
+ memcpy(pbuf, buf, sizeof buf);
+ memset(iv, 0, sizeof iv);
+ ve->run(ec, iv, buf, sizeof buf);
+ }
+ switch (key_len) {
+ case 16:
+ for (k = 0; k < 16; k ++) {
+ key[k] ^= buf[k];
+ }
+ break;
+ case 24:
+ for (k = 0; k < 8; k ++) {
+ key[k] ^= pbuf[8 + k];
+ }
+ for (k = 0; k < 16; k ++) {
+ key[8 + k] ^= buf[k];
+ }
+ break;
+ default:
+ for (k = 0; k < 16; k ++) {
+ key[k] ^= pbuf[k];
+ key[16 + k] ^= buf[k];
+ }
+ break;
+ }
+ printf(".");
+ fflush(stdout);
+ }
+ printf(" ");
+ fflush(stdout);
+ check_equals("MC AES encrypt", buf, cipher, sizeof buf);
+}
+
+static void
+monte_carlo_AES_decrypt(const br_block_cbcdec_class *vd,
+ char *skey, char *scipher, char *splain)
+{
+ unsigned char key[32];
+ unsigned char buf[16];
+ unsigned char pbuf[16];
+ unsigned char plain[16];
+ size_t key_len;
+ int i, j, k;
+ br_aes_gen_cbcdec_keys v_dc;
+ const br_block_cbcdec_class **dc;
+
+ dc = &v_dc.vtable;
+ key_len = hextobin(key, skey);
+ hextobin(buf, scipher);
+ hextobin(plain, splain);
+ for (i = 0; i < 100; i ++) {
+ vd->init(dc, key, key_len);
+ for (j = 0; j < 1000; j ++) {
+ unsigned char iv[16];
+
+ memcpy(pbuf, buf, sizeof buf);
+ memset(iv, 0, sizeof iv);
+ vd->run(dc, iv, buf, sizeof buf);
+ }
+ switch (key_len) {
+ case 16:
+ for (k = 0; k < 16; k ++) {
+ key[k] ^= buf[k];
+ }
+ break;
+ case 24:
+ for (k = 0; k < 8; k ++) {
+ key[k] ^= pbuf[8 + k];
+ }
+ for (k = 0; k < 16; k ++) {
+ key[8 + k] ^= buf[k];
+ }
+ break;
+ default:
+ for (k = 0; k < 16; k ++) {
+ key[k] ^= pbuf[k];
+ key[16 + k] ^= buf[k];
+ }
+ break;
+ }
+ printf(".");
+ fflush(stdout);
+ }
+ printf(" ");
+ fflush(stdout);
+ check_equals("MC AES decrypt", buf, plain, sizeof buf);
+}
+
+static void
+test_AES_generic(char *name,
+ const br_block_cbcenc_class *ve,
+ const br_block_cbcdec_class *vd,
+ const br_block_ctr_class *vc,
+ int with_MC, int with_CBC)
+{
+ size_t u;
+
+ printf("Test %s: ", name);
+ fflush(stdout);
+
+ if (ve->block_size != 16 || vd->block_size != 16
+ || ve->log_block_size != 4 || vd->log_block_size != 4)
+ {
+ fprintf(stderr, "%s failed: wrong block size\n", name);
+ exit(EXIT_FAILURE);
+ }
+
+ for (u = 0; KAT_AES[u]; u += 3) {
+ unsigned char key[32];
+ unsigned char plain[16];
+ unsigned char cipher[16];
+ unsigned char buf[16];
+ unsigned char iv[16];
+ size_t key_len;
+ br_aes_gen_cbcenc_keys v_ec;
+ br_aes_gen_cbcdec_keys v_dc;
+ const br_block_cbcenc_class **ec;
+ const br_block_cbcdec_class **dc;
+
+ ec = &v_ec.vtable;
+ dc = &v_dc.vtable;
+ key_len = hextobin(key, KAT_AES[u]);
+ hextobin(plain, KAT_AES[u + 1]);
+ hextobin(cipher, KAT_AES[u + 2]);
+ ve->init(ec, key, key_len);
+ memcpy(buf, plain, sizeof plain);
+ memset(iv, 0, sizeof iv);
+ ve->run(ec, iv, buf, sizeof buf);
+ check_equals("KAT AES encrypt", buf, cipher, sizeof cipher);
+ vd->init(dc, key, key_len);
+ memset(iv, 0, sizeof iv);
+ vd->run(dc, iv, buf, sizeof buf);
+ check_equals("KAT AES decrypt", buf, plain, sizeof plain);
+ }
+
+ if (with_CBC) {
+ for (u = 0; KAT_AES_CBC[u]; u += 4) {
+ unsigned char key[32];
+ unsigned char ivref[16];
+ unsigned char plain[200];
+ unsigned char cipher[200];
+ unsigned char buf[200];
+ unsigned char iv[16];
+ size_t key_len, data_len, v;
+ br_aes_gen_cbcenc_keys v_ec;
+ br_aes_gen_cbcdec_keys v_dc;
+ const br_block_cbcenc_class **ec;
+ const br_block_cbcdec_class **dc;
+
+ ec = &v_ec.vtable;
+ dc = &v_dc.vtable;
+ key_len = hextobin(key, KAT_AES_CBC[u]);
+ hextobin(ivref, KAT_AES_CBC[u + 1]);
+ data_len = hextobin(plain, KAT_AES_CBC[u + 2]);
+ hextobin(cipher, KAT_AES_CBC[u + 3]);
+ ve->init(ec, key, key_len);
+
+ memcpy(buf, plain, data_len);
+ memcpy(iv, ivref, 16);
+ ve->run(ec, iv, buf, data_len);
+ check_equals("KAT CBC AES encrypt",
+ buf, cipher, data_len);
+ vd->init(dc, key, key_len);
+ memcpy(iv, ivref, 16);
+ vd->run(dc, iv, buf, data_len);
+ check_equals("KAT CBC AES decrypt",
+ buf, plain, data_len);
+
+ memcpy(buf, plain, data_len);
+ memcpy(iv, ivref, 16);
+ for (v = 0; v < data_len; v += 16) {
+ ve->run(ec, iv, buf + v, 16);
+ }
+ check_equals("KAT CBC AES encrypt (2)",
+ buf, cipher, data_len);
+ memcpy(iv, ivref, 16);
+ for (v = 0; v < data_len; v += 16) {
+ vd->run(dc, iv, buf + v, 16);
+ }
+ check_equals("KAT CBC AES decrypt (2)",
+ buf, plain, data_len);
+ }
+ }
+
+ if (vc != NULL) {
+ if (vc->block_size != 16 || vc->log_block_size != 4) {
+ fprintf(stderr, "%s failed: wrong block size\n", name);
+ exit(EXIT_FAILURE);
+ }
+ for (u = 0; KAT_AES_CTR[u]; u += 4) {
+ unsigned char key[32];
+ unsigned char iv[12];
+ unsigned char plain[200];
+ unsigned char cipher[200];
+ unsigned char buf[200];
+ size_t key_len, data_len, v;
+ uint32_t c;
+ br_aes_gen_ctr_keys v_xc;
+ const br_block_ctr_class **xc;
+
+ xc = &v_xc.vtable;
+ key_len = hextobin(key, KAT_AES_CTR[u]);
+ hextobin(iv, KAT_AES_CTR[u + 1]);
+ data_len = hextobin(plain, KAT_AES_CTR[u + 2]);
+ hextobin(cipher, KAT_AES_CTR[u + 3]);
+ vc->init(xc, key, key_len);
+
+ memcpy(buf, plain, data_len);
+ vc->run(xc, iv, 1, buf, data_len);
+ check_equals("KAT CTR AES (1)", buf, cipher, data_len);
+ vc->run(xc, iv, 1, buf, data_len);
+ check_equals("KAT CTR AES (2)", buf, plain, data_len);
+
+ memcpy(buf, plain, data_len);
+ c = 1;
+ for (v = 0; v < data_len; v += 32) {
+ size_t clen;
+
+ clen = data_len - v;
+ if (clen > 32) {
+ clen = 32;
+ }
+ c = vc->run(xc, iv, c, buf + v, clen);
+ }
+ check_equals("KAT CTR AES (3)", buf, cipher, data_len);
+
+ memcpy(buf, plain, data_len);
+ c = 1;
+ for (v = 0; v < data_len; v += 16) {
+ size_t clen;
+
+ clen = data_len - v;
+ if (clen > 16) {
+ clen = 16;
+ }
+ c = vc->run(xc, iv, c, buf + v, clen);
+ }
+ check_equals("KAT CTR AES (4)", buf, cipher, data_len);
+ }
+ }
+
+ if (with_MC) {
+ monte_carlo_AES_encrypt(
+ ve,
+ "139a35422f1d61de3c91787fe0507afd",
+ "b9145a768b7dc489a096b546f43b231f",
+ "fb2649694783b551eacd9d5db6126d47");
+ monte_carlo_AES_decrypt(
+ vd,
+ "0c60e7bf20ada9baa9e1ddf0d1540726",
+ "b08a29b11a500ea3aca42c36675b9785",
+ "d1d2bfdc58ffcad2341b095bce55221e");
+
+ monte_carlo_AES_encrypt(
+ ve,
+ "b9a63e09e1dfc42e93a90d9bad739e5967aef672eedd5da9",
+ "85a1f7a58167b389cddc8a9ff175ee26",
+ "5d1196da8f184975e240949a25104554");
+ monte_carlo_AES_decrypt(
+ vd,
+ "4b97585701c03fbebdfa8555024f589f1482c58a00fdd9fd",
+ "d0bd0e02ded155e4516be83f42d347a4",
+ "b63ef1b79507a62eba3dafcec54a6328");
+
+ monte_carlo_AES_encrypt(
+ ve,
+ "f9e8389f5b80712e3886cc1fa2d28a3b8c9cd88a2d4a54c6aa86ce0fef944be0",
+ "b379777f9050e2a818f2940cbbd9aba4",
+ "c5d2cb3d5b7ff0e23e308967ee074825");
+ monte_carlo_AES_decrypt(
+ vd,
+ "2b09ba39b834062b9e93f48373b8dd018dedf1e5ba1b8af831ebbacbc92a2643",
+ "89649bd0115f30bd878567610223a59d",
+ "e3d3868f578caf34e36445bf14cefc68");
+ }
+
+ printf("done.\n");
+ fflush(stdout);
+}
+
+static void
+test_AES_big(void)
+{
+ test_AES_generic("AES_big",
+ &br_aes_big_cbcenc_vtable,
+ &br_aes_big_cbcdec_vtable,
+ &br_aes_big_ctr_vtable,
+ 1, 1);
+}
+
+static void
+test_AES_small(void)
+{
+ test_AES_generic("AES_small",
+ &br_aes_small_cbcenc_vtable,
+ &br_aes_small_cbcdec_vtable,
+ &br_aes_small_ctr_vtable,
+ 1, 1);
+}
+
+static void
+test_AES_ct(void)
+{
+ test_AES_generic("AES_ct",
+ &br_aes_ct_cbcenc_vtable,
+ &br_aes_ct_cbcdec_vtable,
+ &br_aes_ct_ctr_vtable,
+ 1, 1);
+}
+
+static void
+test_AES_ct64(void)
+{
+ test_AES_generic("AES_ct64",
+ &br_aes_ct64_cbcenc_vtable,
+ &br_aes_ct64_cbcdec_vtable,
+ &br_aes_ct64_ctr_vtable,
+ 1, 1);
+}
+
+/*
+ * DES known-answer tests. Order: plaintext, key, ciphertext.
+ * (mostly from NIST SP 800-20).
+ */
+static const char *const KAT_DES[] = {
+ "10316E028C8F3B4A", "0000000000000000", "82DCBAFBDEAB6602",
+ "8000000000000000", "0000000000000000", "95A8D72813DAA94D",
+ "4000000000000000", "0000000000000000", "0EEC1487DD8C26D5",
+ "2000000000000000", "0000000000000000", "7AD16FFB79C45926",
+ "1000000000000000", "0000000000000000", "D3746294CA6A6CF3",
+ "0800000000000000", "0000000000000000", "809F5F873C1FD761",
+ "0400000000000000", "0000000000000000", "C02FAFFEC989D1FC",
+ "0200000000000000", "0000000000000000", "4615AA1D33E72F10",
+ "0100000000000000", "0000000000000000", "8CA64DE9C1B123A7",
+ "0080000000000000", "0000000000000000", "2055123350C00858",
+ "0040000000000000", "0000000000000000", "DF3B99D6577397C8",
+ "0020000000000000", "0000000000000000", "31FE17369B5288C9",
+ "0010000000000000", "0000000000000000", "DFDD3CC64DAE1642",
+ "0008000000000000", "0000000000000000", "178C83CE2B399D94",
+ "0004000000000000", "0000000000000000", "50F636324A9B7F80",
+ "0002000000000000", "0000000000000000", "A8468EE3BC18F06D",
+ "0001000000000000", "0000000000000000", "8CA64DE9C1B123A7",
+ "0000800000000000", "0000000000000000", "A2DC9E92FD3CDE92",
+ "0000400000000000", "0000000000000000", "CAC09F797D031287",
+ "0000200000000000", "0000000000000000", "90BA680B22AEB525",
+ "0000100000000000", "0000000000000000", "CE7A24F350E280B6",
+ "0000080000000000", "0000000000000000", "882BFF0AA01A0B87",
+ "0000040000000000", "0000000000000000", "25610288924511C2",
+ "0000020000000000", "0000000000000000", "C71516C29C75D170",
+ "0000010000000000", "0000000000000000", "8CA64DE9C1B123A7",
+ "0000008000000000", "0000000000000000", "5199C29A52C9F059",
+ "0000004000000000", "0000000000000000", "C22F0A294A71F29F",
+ "0000002000000000", "0000000000000000", "EE371483714C02EA",
+ "0000001000000000", "0000000000000000", "A81FBD448F9E522F",
+ "0000000800000000", "0000000000000000", "4F644C92E192DFED",
+ "0000000400000000", "0000000000000000", "1AFA9A66A6DF92AE",
+ "0000000200000000", "0000000000000000", "B3C1CC715CB879D8",
+ "0000000100000000", "0000000000000000", "8CA64DE9C1B123A7",
+ "0000000080000000", "0000000000000000", "19D032E64AB0BD8B",
+ "0000000040000000", "0000000000000000", "3CFAA7A7DC8720DC",
+ "0000000020000000", "0000000000000000", "B7265F7F447AC6F3",
+ "0000000010000000", "0000000000000000", "9DB73B3C0D163F54",
+ "0000000008000000", "0000000000000000", "8181B65BABF4A975",
+ "0000000004000000", "0000000000000000", "93C9B64042EAA240",
+ "0000000002000000", "0000000000000000", "5570530829705592",
+ "0000000001000000", "0000000000000000", "8CA64DE9C1B123A7",
+ "0000000000800000", "0000000000000000", "8638809E878787A0",
+ "0000000000400000", "0000000000000000", "41B9A79AF79AC208",
+ "0000000000200000", "0000000000000000", "7A9BE42F2009A892",
+ "0000000000100000", "0000000000000000", "29038D56BA6D2745",
+ "0000000000080000", "0000000000000000", "5495C6ABF1E5DF51",
+ "0000000000040000", "0000000000000000", "AE13DBD561488933",
+ "0000000000020000", "0000000000000000", "024D1FFA8904E389",
+ "0000000000010000", "0000000000000000", "8CA64DE9C1B123A7",
+ "0000000000008000", "0000000000000000", "D1399712F99BF02E",
+ "0000000000004000", "0000000000000000", "14C1D7C1CFFEC79E",
+ "0000000000002000", "0000000000000000", "1DE5279DAE3BED6F",
+ "0000000000001000", "0000000000000000", "E941A33F85501303",
+ "0000000000000800", "0000000000000000", "DA99DBBC9A03F379",
+ "0000000000000400", "0000000000000000", "B7FC92F91D8E92E9",
+ "0000000000000200", "0000000000000000", "AE8E5CAA3CA04E85",
+ "0000000000000100", "0000000000000000", "8CA64DE9C1B123A7",
+ "0000000000000080", "0000000000000000", "9CC62DF43B6EED74",
+ "0000000000000040", "0000000000000000", "D863DBB5C59A91A0",
+ "0000000000000020", "0000000000000000", "A1AB2190545B91D7",
+ "0000000000000010", "0000000000000000", "0875041E64C570F7",
+ "0000000000000008", "0000000000000000", "5A594528BEBEF1CC",
+ "0000000000000004", "0000000000000000", "FCDB3291DE21F0C0",
+ "0000000000000002", "0000000000000000", "869EFD7F9F265A09",
+ "0000000000000001", "0000000000000000", "8CA64DE9C1B123A7",
+ "0000000000000000", "8000000000000000", "95F8A5E5DD31D900",
+ "0000000000000000", "4000000000000000", "DD7F121CA5015619",
+ "0000000000000000", "2000000000000000", "2E8653104F3834EA",
+ "0000000000000000", "1000000000000000", "4BD388FF6CD81D4F",
+ "0000000000000000", "0800000000000000", "20B9E767B2FB1456",
+ "0000000000000000", "0400000000000000", "55579380D77138EF",
+ "0000000000000000", "0200000000000000", "6CC5DEFAAF04512F",
+ "0000000000000000", "0100000000000000", "0D9F279BA5D87260",
+ "0000000000000000", "0080000000000000", "D9031B0271BD5A0A",
+ "0000000000000000", "0040000000000000", "424250B37C3DD951",
+ "0000000000000000", "0020000000000000", "B8061B7ECD9A21E5",
+ "0000000000000000", "0010000000000000", "F15D0F286B65BD28",
+ "0000000000000000", "0008000000000000", "ADD0CC8D6E5DEBA1",
+ "0000000000000000", "0004000000000000", "E6D5F82752AD63D1",
+ "0000000000000000", "0002000000000000", "ECBFE3BD3F591A5E",
+ "0000000000000000", "0001000000000000", "F356834379D165CD",
+ "0000000000000000", "0000800000000000", "2B9F982F20037FA9",
+ "0000000000000000", "0000400000000000", "889DE068A16F0BE6",
+ "0000000000000000", "0000200000000000", "E19E275D846A1298",
+ "0000000000000000", "0000100000000000", "329A8ED523D71AEC",
+ "0000000000000000", "0000080000000000", "E7FCE22557D23C97",
+ "0000000000000000", "0000040000000000", "12A9F5817FF2D65D",
+ "0000000000000000", "0000020000000000", "A484C3AD38DC9C19",
+ "0000000000000000", "0000010000000000", "FBE00A8A1EF8AD72",
+ "0000000000000000", "0000008000000000", "750D079407521363",
+ "0000000000000000", "0000004000000000", "64FEED9C724C2FAF",
+ "0000000000000000", "0000002000000000", "F02B263B328E2B60",
+ "0000000000000000", "0000001000000000", "9D64555A9A10B852",
+ "0000000000000000", "0000000800000000", "D106FF0BED5255D7",
+ "0000000000000000", "0000000400000000", "E1652C6B138C64A5",
+ "0000000000000000", "0000000200000000", "E428581186EC8F46",
+ "0000000000000000", "0000000100000000", "AEB5F5EDE22D1A36",
+ "0000000000000000", "0000000080000000", "E943D7568AEC0C5C",
+ "0000000000000000", "0000000040000000", "DF98C8276F54B04B",
+ "0000000000000000", "0000000020000000", "B160E4680F6C696F",
+ "0000000000000000", "0000000010000000", "FA0752B07D9C4AB8",
+ "0000000000000000", "0000000008000000", "CA3A2B036DBC8502",
+ "0000000000000000", "0000000004000000", "5E0905517BB59BCF",
+ "0000000000000000", "0000000002000000", "814EEB3B91D90726",
+ "0000000000000000", "0000000001000000", "4D49DB1532919C9F",
+ "0000000000000000", "0000000000800000", "25EB5FC3F8CF0621",
+ "0000000000000000", "0000000000400000", "AB6A20C0620D1C6F",
+ "0000000000000000", "0000000000200000", "79E90DBC98F92CCA",
+ "0000000000000000", "0000000000100000", "866ECEDD8072BB0E",
+ "0000000000000000", "0000000000080000", "8B54536F2F3E64A8",
+ "0000000000000000", "0000000000040000", "EA51D3975595B86B",
+ "0000000000000000", "0000000000020000", "CAFFC6AC4542DE31",
+ "0000000000000000", "0000000000010000", "8DD45A2DDF90796C",
+ "0000000000000000", "0000000000008000", "1029D55E880EC2D0",
+ "0000000000000000", "0000000000004000", "5D86CB23639DBEA9",
+ "0000000000000000", "0000000000002000", "1D1CA853AE7C0C5F",
+ "0000000000000000", "0000000000001000", "CE332329248F3228",
+ "0000000000000000", "0000000000000800", "8405D1ABE24FB942",
+ "0000000000000000", "0000000000000400", "E643D78090CA4207",
+ "0000000000000000", "0000000000000200", "48221B9937748A23",
+ "0000000000000000", "0000000000000100", "DD7C0BBD61FAFD54",
+ "0000000000000000", "0000000000000080", "2FBC291A570DB5C4",
+ "0000000000000000", "0000000000000040", "E07C30D7E4E26E12",
+ "0000000000000000", "0000000000000020", "0953E2258E8E90A1",
+ "0000000000000000", "0000000000000010", "5B711BC4CEEBF2EE",
+ "0000000000000000", "0000000000000008", "CC083F1E6D9E85F6",
+ "0000000000000000", "0000000000000004", "D2FD8867D50D2DFE",
+ "0000000000000000", "0000000000000002", "06E7EA22CE92708F",
+ "0000000000000000", "0000000000000001", "166B40B44ABA4BD6",
+ "0000000000000000", "0000000000000000", "8CA64DE9C1B123A7",
+ "0101010101010101", "0101010101010101", "994D4DC157B96C52",
+ "0202020202020202", "0202020202020202", "E127C2B61D98E6E2",
+ "0303030303030303", "0303030303030303", "984C91D78A269CE3",
+ "0404040404040404", "0404040404040404", "1F4570BB77550683",
+ "0505050505050505", "0505050505050505", "3990ABF98D672B16",
+ "0606060606060606", "0606060606060606", "3F5150BBA081D585",
+ "0707070707070707", "0707070707070707", "C65242248C9CF6F2",
+ "0808080808080808", "0808080808080808", "10772D40FAD24257",
+ "0909090909090909", "0909090909090909", "F0139440647A6E7B",
+ "0A0A0A0A0A0A0A0A", "0A0A0A0A0A0A0A0A", "0A288603044D740C",
+ "0B0B0B0B0B0B0B0B", "0B0B0B0B0B0B0B0B", "6359916942F7438F",
+ "0C0C0C0C0C0C0C0C", "0C0C0C0C0C0C0C0C", "934316AE443CF08B",
+ "0D0D0D0D0D0D0D0D", "0D0D0D0D0D0D0D0D", "E3F56D7F1130A2B7",
+ "0E0E0E0E0E0E0E0E", "0E0E0E0E0E0E0E0E", "A2E4705087C6B6B4",
+ "0F0F0F0F0F0F0F0F", "0F0F0F0F0F0F0F0F", "D5D76E09A447E8C3",
+ "1010101010101010", "1010101010101010", "DD7515F2BFC17F85",
+ "1111111111111111", "1111111111111111", "F40379AB9E0EC533",
+ "1212121212121212", "1212121212121212", "96CD27784D1563E5",
+ "1313131313131313", "1313131313131313", "2911CF5E94D33FE1",
+ "1414141414141414", "1414141414141414", "377B7F7CA3E5BBB3",
+ "1515151515151515", "1515151515151515", "701AA63832905A92",
+ "1616161616161616", "1616161616161616", "2006E716C4252D6D",
+ "1717171717171717", "1717171717171717", "452C1197422469F8",
+ "1818181818181818", "1818181818181818", "C33FD1EB49CB64DA",
+ "1919191919191919", "1919191919191919", "7572278F364EB50D",
+ "1A1A1A1A1A1A1A1A", "1A1A1A1A1A1A1A1A", "69E51488403EF4C3",
+ "1B1B1B1B1B1B1B1B", "1B1B1B1B1B1B1B1B", "FF847E0ADF192825",
+ "1C1C1C1C1C1C1C1C", "1C1C1C1C1C1C1C1C", "521B7FB3B41BB791",
+ "1D1D1D1D1D1D1D1D", "1D1D1D1D1D1D1D1D", "26059A6A0F3F6B35",
+ "1E1E1E1E1E1E1E1E", "1E1E1E1E1E1E1E1E", "F24A8D2231C77538",
+ "1F1F1F1F1F1F1F1F", "1F1F1F1F1F1F1F1F", "4FD96EC0D3304EF6",
+ "2020202020202020", "2020202020202020", "18A9D580A900B699",
+ "2121212121212121", "2121212121212121", "88586E1D755B9B5A",
+ "2222222222222222", "2222222222222222", "0F8ADFFB11DC2784",
+ "2323232323232323", "2323232323232323", "2F30446C8312404A",
+ "2424242424242424", "2424242424242424", "0BA03D9E6C196511",
+ "2525252525252525", "2525252525252525", "3E55E997611E4B7D",
+ "2626262626262626", "2626262626262626", "B2522FB5F158F0DF",
+ "2727272727272727", "2727272727272727", "2109425935406AB8",
+ "2828282828282828", "2828282828282828", "11A16028F310FF16",
+ "2929292929292929", "2929292929292929", "73F0C45F379FE67F",
+ "2A2A2A2A2A2A2A2A", "2A2A2A2A2A2A2A2A", "DCAD4338F7523816",
+ "2B2B2B2B2B2B2B2B", "2B2B2B2B2B2B2B2B", "B81634C1CEAB298C",
+ "2C2C2C2C2C2C2C2C", "2C2C2C2C2C2C2C2C", "DD2CCB29B6C4C349",
+ "2D2D2D2D2D2D2D2D", "2D2D2D2D2D2D2D2D", "7D07A77A2ABD50A7",
+ "2E2E2E2E2E2E2E2E", "2E2E2E2E2E2E2E2E", "30C1B0C1FD91D371",
+ "2F2F2F2F2F2F2F2F", "2F2F2F2F2F2F2F2F", "C4427B31AC61973B",
+ "3030303030303030", "3030303030303030", "F47BB46273B15EB5",
+ "3131313131313131", "3131313131313131", "655EA628CF62585F",
+ "3232323232323232", "3232323232323232", "AC978C247863388F",
+ "3333333333333333", "3333333333333333", "0432ED386F2DE328",
+ "3434343434343434", "3434343434343434", "D254014CB986B3C2",
+ "3535353535353535", "3535353535353535", "B256E34BEDB49801",
+ "3636363636363636", "3636363636363636", "37F8759EB77E7BFC",
+ "3737373737373737", "3737373737373737", "5013CA4F62C9CEA0",
+ "3838383838383838", "3838383838383838", "8940F7B3EACA5939",
+ "3939393939393939", "3939393939393939", "E22B19A55086774B",
+ "3A3A3A3A3A3A3A3A", "3A3A3A3A3A3A3A3A", "B04A2AAC925ABB0B",
+ "3B3B3B3B3B3B3B3B", "3B3B3B3B3B3B3B3B", "8D250D58361597FC",
+ "3C3C3C3C3C3C3C3C", "3C3C3C3C3C3C3C3C", "51F0114FB6A6CD37",
+ "3D3D3D3D3D3D3D3D", "3D3D3D3D3D3D3D3D", "9D0BB4DB830ECB73",
+ "3E3E3E3E3E3E3E3E", "3E3E3E3E3E3E3E3E", "E96089D6368F3E1A",
+ "3F3F3F3F3F3F3F3F", "3F3F3F3F3F3F3F3F", "5C4CA877A4E1E92D",
+ "4040404040404040", "4040404040404040", "6D55DDBC8DEA95FF",
+ "4141414141414141", "4141414141414141", "19DF84AC95551003",
+ "4242424242424242", "4242424242424242", "724E7332696D08A7",
+ "4343434343434343", "4343434343434343", "B91810B8CDC58FE2",
+ "4444444444444444", "4444444444444444", "06E23526EDCCD0C4",
+ "4545454545454545", "4545454545454545", "EF52491D5468D441",
+ "4646464646464646", "4646464646464646", "48019C59E39B90C5",
+ "4747474747474747", "4747474747474747", "0544083FB902D8C0",
+ "4848484848484848", "4848484848484848", "63B15CADA668CE12",
+ "4949494949494949", "4949494949494949", "EACC0C1264171071",
+ "4A4A4A4A4A4A4A4A", "4A4A4A4A4A4A4A4A", "9D2B8C0AC605F274",
+ "4B4B4B4B4B4B4B4B", "4B4B4B4B4B4B4B4B", "C90F2F4C98A8FB2A",
+ "4C4C4C4C4C4C4C4C", "4C4C4C4C4C4C4C4C", "03481B4828FD1D04",
+ "4D4D4D4D4D4D4D4D", "4D4D4D4D4D4D4D4D", "C78FC45A1DCEA2E2",
+ "4E4E4E4E4E4E4E4E", "4E4E4E4E4E4E4E4E", "DB96D88C3460D801",
+ "4F4F4F4F4F4F4F4F", "4F4F4F4F4F4F4F4F", "6C69E720F5105518",
+ "5050505050505050", "5050505050505050", "0D262E418BC893F3",
+ "5151515151515151", "5151515151515151", "6AD84FD7848A0A5C",
+ "5252525252525252", "5252525252525252", "C365CB35B34B6114",
+ "5353535353535353", "5353535353535353", "1155392E877F42A9",
+ "5454545454545454", "5454545454545454", "531BE5F9405DA715",
+ "5555555555555555", "5555555555555555", "3BCDD41E6165A5E8",
+ "5656565656565656", "5656565656565656", "2B1FF5610A19270C",
+ "5757575757575757", "5757575757575757", "D90772CF3F047CFD",
+ "5858585858585858", "5858585858585858", "1BEA27FFB72457B7",
+ "5959595959595959", "5959595959595959", "85C3E0C429F34C27",
+ "5A5A5A5A5A5A5A5A", "5A5A5A5A5A5A5A5A", "F9038021E37C7618",
+ "5B5B5B5B5B5B5B5B", "5B5B5B5B5B5B5B5B", "35BC6FF838DBA32F",
+ "5C5C5C5C5C5C5C5C", "5C5C5C5C5C5C5C5C", "4927ACC8CE45ECE7",
+ "5D5D5D5D5D5D5D5D", "5D5D5D5D5D5D5D5D", "E812EE6E3572985C",
+ "5E5E5E5E5E5E5E5E", "5E5E5E5E5E5E5E5E", "9BB93A89627BF65F",
+ "5F5F5F5F5F5F5F5F", "5F5F5F5F5F5F5F5F", "EF12476884CB74CA",
+ "6060606060606060", "6060606060606060", "1BF17E00C09E7CBF",
+ "6161616161616161", "6161616161616161", "29932350C098DB5D",
+ "6262626262626262", "6262626262626262", "B476E6499842AC54",
+ "6363636363636363", "6363636363636363", "5C662C29C1E96056",
+ "6464646464646464", "6464646464646464", "3AF1703D76442789",
+ "6565656565656565", "6565656565656565", "86405D9B425A8C8C",
+ "6666666666666666", "6666666666666666", "EBBF4810619C2C55",
+ "6767676767676767", "6767676767676767", "F8D1CD7367B21B5D",
+ "6868686868686868", "6868686868686868", "9EE703142BF8D7E2",
+ "6969696969696969", "6969696969696969", "5FDFFFC3AAAB0CB3",
+ "6A6A6A6A6A6A6A6A", "6A6A6A6A6A6A6A6A", "26C940AB13574231",
+ "6B6B6B6B6B6B6B6B", "6B6B6B6B6B6B6B6B", "1E2DC77E36A84693",
+ "6C6C6C6C6C6C6C6C", "6C6C6C6C6C6C6C6C", "0F4FF4D9BC7E2244",
+ "6D6D6D6D6D6D6D6D", "6D6D6D6D6D6D6D6D", "A4C9A0D04D3280CD",
+ "6E6E6E6E6E6E6E6E", "6E6E6E6E6E6E6E6E", "9FAF2C96FE84919D",
+ "6F6F6F6F6F6F6F6F", "6F6F6F6F6F6F6F6F", "115DBC965E6096C8",
+ "7070707070707070", "7070707070707070", "AF531E9520994017",
+ "7171717171717171", "7171717171717171", "B971ADE70E5C89EE",
+ "7272727272727272", "7272727272727272", "415D81C86AF9C376",
+ "7373737373737373", "7373737373737373", "8DFB864FDB3C6811",
+ "7474747474747474", "7474747474747474", "10B1C170E3398F91",
+ "7575757575757575", "7575757575757575", "CFEF7A1C0218DB1E",
+ "7676767676767676", "7676767676767676", "DBAC30A2A40B1B9C",
+ "7777777777777777", "7777777777777777", "89D3BF37052162E9",
+ "7878787878787878", "7878787878787878", "80D9230BDAEB67DC",
+ "7979797979797979", "7979797979797979", "3440911019AD68D7",
+ "7A7A7A7A7A7A7A7A", "7A7A7A7A7A7A7A7A", "9626FE57596E199E",
+ "7B7B7B7B7B7B7B7B", "7B7B7B7B7B7B7B7B", "DEA0B796624BB5BA",
+ "7C7C7C7C7C7C7C7C", "7C7C7C7C7C7C7C7C", "E9E40542BDDB3E9D",
+ "7D7D7D7D7D7D7D7D", "7D7D7D7D7D7D7D7D", "8AD99914B354B911",
+ "7E7E7E7E7E7E7E7E", "7E7E7E7E7E7E7E7E", "6F85B98DD12CB13B",
+ "7F7F7F7F7F7F7F7F", "7F7F7F7F7F7F7F7F", "10130DA3C3A23924",
+ "8080808080808080", "8080808080808080", "EFECF25C3C5DC6DB",
+ "8181818181818181", "8181818181818181", "907A46722ED34EC4",
+ "8282828282828282", "8282828282828282", "752666EB4CAB46EE",
+ "8383838383838383", "8383838383838383", "161BFABD4224C162",
+ "8484848484848484", "8484848484848484", "215F48699DB44A45",
+ "8585858585858585", "8585858585858585", "69D901A8A691E661",
+ "8686868686868686", "8686868686868686", "CBBF6EEFE6529728",
+ "8787878787878787", "8787878787878787", "7F26DCF425149823",
+ "8888888888888888", "8888888888888888", "762C40C8FADE9D16",
+ "8989898989898989", "8989898989898989", "2453CF5D5BF4E463",
+ "8A8A8A8A8A8A8A8A", "8A8A8A8A8A8A8A8A", "301085E3FDE724E1",
+ "8B8B8B8B8B8B8B8B", "8B8B8B8B8B8B8B8B", "EF4E3E8F1CC6706E",
+ "8C8C8C8C8C8C8C8C", "8C8C8C8C8C8C8C8C", "720479B024C397EE",
+ "8D8D8D8D8D8D8D8D", "8D8D8D8D8D8D8D8D", "BEA27E3795063C89",
+ "8E8E8E8E8E8E8E8E", "8E8E8E8E8E8E8E8E", "468E5218F1A37611",
+ "8F8F8F8F8F8F8F8F", "8F8F8F8F8F8F8F8F", "50ACE16ADF66BFE8",
+ "9090909090909090", "9090909090909090", "EEA24369A19F6937",
+ "9191919191919191", "9191919191919191", "6050D369017B6E62",
+ "9292929292929292", "9292929292929292", "5B365F2FB2CD7F32",
+ "9393939393939393", "9393939393939393", "F0B00B264381DDBB",
+ "9494949494949494", "9494949494949494", "E1D23881C957B96C",
+ "9595959595959595", "9595959595959595", "D936BF54ECA8BDCE",
+ "9696969696969696", "9696969696969696", "A020003C5554F34C",
+ "9797979797979797", "9797979797979797", "6118FCEBD407281D",
+ "9898989898989898", "9898989898989898", "072E328C984DE4A2",
+ "9999999999999999", "9999999999999999", "1440B7EF9E63D3AA",
+ "9A9A9A9A9A9A9A9A", "9A9A9A9A9A9A9A9A", "79BFA264BDA57373",
+ "9B9B9B9B9B9B9B9B", "9B9B9B9B9B9B9B9B", "C50E8FC289BBD876",
+ "9C9C9C9C9C9C9C9C", "9C9C9C9C9C9C9C9C", "A399D3D63E169FA9",
+ "9D9D9D9D9D9D9D9D", "9D9D9D9D9D9D9D9D", "4B8919B667BD53AB",
+ "9E9E9E9E9E9E9E9E", "9E9E9E9E9E9E9E9E", "D66CDCAF3F6724A2",
+ "9F9F9F9F9F9F9F9F", "9F9F9F9F9F9F9F9F", "E40E81FF3F618340",
+ "A0A0A0A0A0A0A0A0", "A0A0A0A0A0A0A0A0", "10EDB8977B348B35",
+ "A1A1A1A1A1A1A1A1", "A1A1A1A1A1A1A1A1", "6446C5769D8409A0",
+ "A2A2A2A2A2A2A2A2", "A2A2A2A2A2A2A2A2", "17ED1191CA8D67A3",
+ "A3A3A3A3A3A3A3A3", "A3A3A3A3A3A3A3A3", "B6D8533731BA1318",
+ "A4A4A4A4A4A4A4A4", "A4A4A4A4A4A4A4A4", "CA439007C7245CD0",
+ "A5A5A5A5A5A5A5A5", "A5A5A5A5A5A5A5A5", "06FC7FDE1C8389E7",
+ "A6A6A6A6A6A6A6A6", "A6A6A6A6A6A6A6A6", "7A3C1F3BD60CB3D8",
+ "A7A7A7A7A7A7A7A7", "A7A7A7A7A7A7A7A7", "E415D80048DBA848",
+ "A8A8A8A8A8A8A8A8", "A8A8A8A8A8A8A8A8", "26F88D30C0FB8302",
+ "A9A9A9A9A9A9A9A9", "A9A9A9A9A9A9A9A9", "D4E00A9EF5E6D8F3",
+ "AAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAA", "C4322BE19E9A5A17",
+ "ABABABABABABABAB", "ABABABABABABABAB", "ACE41A06BFA258EA",
+ "ACACACACACACACAC", "ACACACACACACACAC", "EEAAC6D17880BD56",
+ "ADADADADADADADAD", "ADADADADADADADAD", "3C9A34CA4CB49EEB",
+ "AEAEAEAEAEAEAEAE", "AEAEAEAEAEAEAEAE", "9527B0287B75F5A3",
+ "AFAFAFAFAFAFAFAF", "AFAFAFAFAFAFAFAF", "F2D9D1BE74376C0C",
+ "B0B0B0B0B0B0B0B0", "B0B0B0B0B0B0B0B0", "939618DF0AEFAAE7",
+ "B1B1B1B1B1B1B1B1", "B1B1B1B1B1B1B1B1", "24692773CB9F27FE",
+ "B2B2B2B2B2B2B2B2", "B2B2B2B2B2B2B2B2", "38703BA5E2315D1D",
+ "B3B3B3B3B3B3B3B3", "B3B3B3B3B3B3B3B3", "FCB7E4B7D702E2FB",
+ "B4B4B4B4B4B4B4B4", "B4B4B4B4B4B4B4B4", "36F0D0B3675704D5",
+ "B5B5B5B5B5B5B5B5", "B5B5B5B5B5B5B5B5", "62D473F539FA0D8B",
+ "B6B6B6B6B6B6B6B6", "B6B6B6B6B6B6B6B6", "1533F3ED9BE8EF8E",
+ "B7B7B7B7B7B7B7B7", "B7B7B7B7B7B7B7B7", "9C4EA352599731ED",
+ "B8B8B8B8B8B8B8B8", "B8B8B8B8B8B8B8B8", "FABBF7C046FD273F",
+ "B9B9B9B9B9B9B9B9", "B9B9B9B9B9B9B9B9", "B7FE63A61C646F3A",
+ "BABABABABABABABA", "BABABABABABABABA", "10ADB6E2AB972BBE",
+ "BBBBBBBBBBBBBBBB", "BBBBBBBBBBBBBBBB", "F91DCAD912332F3B",
+ "BCBCBCBCBCBCBCBC", "BCBCBCBCBCBCBCBC", "46E7EF47323A701D",
+ "BDBDBDBDBDBDBDBD", "BDBDBDBDBDBDBDBD", "8DB18CCD9692F758",
+ "BEBEBEBEBEBEBEBE", "BEBEBEBEBEBEBEBE", "E6207B536AAAEFFC",
+ "BFBFBFBFBFBFBFBF", "BFBFBFBFBFBFBFBF", "92AA224372156A00",
+ "C0C0C0C0C0C0C0C0", "C0C0C0C0C0C0C0C0", "A3B357885B1E16D2",
+ "C1C1C1C1C1C1C1C1", "C1C1C1C1C1C1C1C1", "169F7629C970C1E5",
+ "C2C2C2C2C2C2C2C2", "C2C2C2C2C2C2C2C2", "62F44B247CF1348C",
+ "C3C3C3C3C3C3C3C3", "C3C3C3C3C3C3C3C3", "AE0FEEB0495932C8",
+ "C4C4C4C4C4C4C4C4", "C4C4C4C4C4C4C4C4", "72DAF2A7C9EA6803",
+ "C5C5C5C5C5C5C5C5", "C5C5C5C5C5C5C5C5", "4FB5D5536DA544F4",
+ "C6C6C6C6C6C6C6C6", "C6C6C6C6C6C6C6C6", "1DD4E65AAF7988B4",
+ "C7C7C7C7C7C7C7C7", "C7C7C7C7C7C7C7C7", "76BF084C1535A6C6",
+ "C8C8C8C8C8C8C8C8", "C8C8C8C8C8C8C8C8", "AFEC35B09D36315F",
+ "C9C9C9C9C9C9C9C9", "C9C9C9C9C9C9C9C9", "C8078A6148818403",
+ "CACACACACACACACA", "CACACACACACACACA", "4DA91CB4124B67FE",
+ "CBCBCBCBCBCBCBCB", "CBCBCBCBCBCBCBCB", "2DABFEB346794C3D",
+ "CCCCCCCCCCCCCCCC", "CCCCCCCCCCCCCCCC", "FBCD12C790D21CD7",
+ "CDCDCDCDCDCDCDCD", "CDCDCDCDCDCDCDCD", "536873DB879CC770",
+ "CECECECECECECECE", "CECECECECECECECE", "9AA159D7309DA7A0",
+ "CFCFCFCFCFCFCFCF", "CFCFCFCFCFCFCFCF", "0B844B9D8C4EA14A",
+ "D0D0D0D0D0D0D0D0", "D0D0D0D0D0D0D0D0", "3BBD84CE539E68C4",
+ "D1D1D1D1D1D1D1D1", "D1D1D1D1D1D1D1D1", "CF3E4F3E026E2C8E",
+ "D2D2D2D2D2D2D2D2", "D2D2D2D2D2D2D2D2", "82F85885D542AF58",
+ "D3D3D3D3D3D3D3D3", "D3D3D3D3D3D3D3D3", "22D334D6493B3CB6",
+ "D4D4D4D4D4D4D4D4", "D4D4D4D4D4D4D4D4", "47E9CB3E3154D673",
+ "D5D5D5D5D5D5D5D5", "D5D5D5D5D5D5D5D5", "2352BCC708ADC7E9",
+ "D6D6D6D6D6D6D6D6", "D6D6D6D6D6D6D6D6", "8C0F3BA0C8601980",
+ "D7D7D7D7D7D7D7D7", "D7D7D7D7D7D7D7D7", "EE5E9FD70CEF00E9",
+ "D8D8D8D8D8D8D8D8", "D8D8D8D8D8D8D8D8", "DEF6BDA6CABF9547",
+ "D9D9D9D9D9D9D9D9", "D9D9D9D9D9D9D9D9", "4DADD04A0EA70F20",
+ "DADADADADADADADA", "DADADADADADADADA", "C1AA16689EE1B482",
+ "DBDBDBDBDBDBDBDB", "DBDBDBDBDBDBDBDB", "F45FC26193E69AEE",
+ "DCDCDCDCDCDCDCDC", "DCDCDCDCDCDCDCDC", "D0CFBB937CEDBFB5",
+ "DDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDD", "F0752004EE23D87B",
+ "DEDEDEDEDEDEDEDE", "DEDEDEDEDEDEDEDE", "77A791E28AA464A5",
+ "DFDFDFDFDFDFDFDF", "DFDFDFDFDFDFDFDF", "E7562A7F56FF4966",
+ "E0E0E0E0E0E0E0E0", "E0E0E0E0E0E0E0E0", "B026913F2CCFB109",
+ "E1E1E1E1E1E1E1E1", "E1E1E1E1E1E1E1E1", "0DB572DDCE388AC7",
+ "E2E2E2E2E2E2E2E2", "E2E2E2E2E2E2E2E2", "D9FA6595F0C094CA",
+ "E3E3E3E3E3E3E3E3", "E3E3E3E3E3E3E3E3", "ADE4804C4BE4486E",
+ "E4E4E4E4E4E4E4E4", "E4E4E4E4E4E4E4E4", "007B81F520E6D7DA",
+ "E5E5E5E5E5E5E5E5", "E5E5E5E5E5E5E5E5", "961AEB77BFC10B3C",
+ "E6E6E6E6E6E6E6E6", "E6E6E6E6E6E6E6E6", "8A8DD870C9B14AF2",
+ "E7E7E7E7E7E7E7E7", "E7E7E7E7E7E7E7E7", "3CC02E14B6349B25",
+ "E8E8E8E8E8E8E8E8", "E8E8E8E8E8E8E8E8", "BAD3EE68BDDB9607",
+ "E9E9E9E9E9E9E9E9", "E9E9E9E9E9E9E9E9", "DFF918E93BDAD292",
+ "EAEAEAEAEAEAEAEA", "EAEAEAEAEAEAEAEA", "8FE559C7CD6FA56D",
+ "EBEBEBEBEBEBEBEB", "EBEBEBEBEBEBEBEB", "C88480835C1A444C",
+ "ECECECECECECECEC", "ECECECECECECECEC", "D6EE30A16B2CC01E",
+ "EDEDEDEDEDEDEDED", "EDEDEDEDEDEDEDED", "6932D887B2EA9C1A",
+ "EEEEEEEEEEEEEEEE", "EEEEEEEEEEEEEEEE", "0BFC865461F13ACC",
+ "EFEFEFEFEFEFEFEF", "EFEFEFEFEFEFEFEF", "228AEA0D403E807A",
+ "F0F0F0F0F0F0F0F0", "F0F0F0F0F0F0F0F0", "2A2891F65BB8173C",
+ "F1F1F1F1F1F1F1F1", "F1F1F1F1F1F1F1F1", "5D1B8FAF7839494B",
+ "F2F2F2F2F2F2F2F2", "F2F2F2F2F2F2F2F2", "1C0A9280EECF5D48",
+ "F3F3F3F3F3F3F3F3", "F3F3F3F3F3F3F3F3", "6CBCE951BBC30F74",
+ "F4F4F4F4F4F4F4F4", "F4F4F4F4F4F4F4F4", "9CA66E96BD08BC70",
+ "F5F5F5F5F5F5F5F5", "F5F5F5F5F5F5F5F5", "F5D779FCFBB28BF3",
+ "F6F6F6F6F6F6F6F6", "F6F6F6F6F6F6F6F6", "0FEC6BBF9B859184",
+ "F7F7F7F7F7F7F7F7", "F7F7F7F7F7F7F7F7", "EF88D2BF052DBDA8",
+ "F8F8F8F8F8F8F8F8", "F8F8F8F8F8F8F8F8", "39ADBDDB7363090D",
+ "F9F9F9F9F9F9F9F9", "F9F9F9F9F9F9F9F9", "C0AEAF445F7E2A7A",
+ "FAFAFAFAFAFAFAFA", "FAFAFAFAFAFAFAFA", "C66F54067298D4E9",
+ "FBFBFBFBFBFBFBFB", "FBFBFBFBFBFBFBFB", "E0BA8F4488AAF97C",
+ "FCFCFCFCFCFCFCFC", "FCFCFCFCFCFCFCFC", "67B36E2875D9631C",
+ "FDFDFDFDFDFDFDFD", "FDFDFDFDFDFDFDFD", "1ED83D49E267191D",
+ "FEFEFEFEFEFEFEFE", "FEFEFEFEFEFEFEFE", "66B2B23EA84693AD",
+ "FFFFFFFFFFFFFFFF", "FFFFFFFFFFFFFFFF", "7359B2163E4EDC58",
+ "0001020304050607", "0011223344556677", "3EF0A891CF8ED990",
+ "2BD6459F82C5B300", "EA024714AD5C4D84", "126EFE8ED312190A",
+
+ NULL
+};
+
+/*
+ * Known-answer tests for DES/3DES in CBC mode. Order: key, IV,
+ * plaintext, ciphertext.
+ */
+static const char *const KAT_DES_CBC[] = {
+ /*
+ * From NIST validation suite (tdesmmt.zip).
+ */
+ "34a41a8c293176c1b30732ecfe38ae8a34a41a8c293176c1",
+ "f55b4855228bd0b4",
+ "7dd880d2a9ab411c",
+ "c91892948b6cadb4",
+
+ "70a88fa1dfb9942fa77f40157ffef2ad70a88fa1dfb9942f",
+ "ece08ce2fdc6ce80",
+ "bc225304d5a3a5c9918fc5006cbc40cc",
+ "27f67dc87af7ddb4b68f63fa7c2d454a",
+
+ "e091790be55be0bc0780153861a84adce091790be55be0bc",
+ "fd7d430f86fbbffe",
+ "03c7fffd7f36499c703dedc9df4de4a92dd4382e576d6ae9",
+ "053aeba85dd3a23bfbe8440a432f9578f312be60fb9f0035",
+
+ "857feacd16157c58e5347a70e56e578a857feacd16157c58",
+ "002dcb6d46ef0969",
+ "1f13701c7f0d7385307507a18e89843ebd295bd5e239ef109347a6898c6d3fd5",
+ "a0e4edde34f05bd8397ce279e49853e9387ba04be562f5fa19c3289c3f5a3391",
+
+ "a173545b265875ba852331fbb95b49a8a173545b265875ba",
+ "ab385756391d364c",
+ "d08894c565608d9ae51dda63b85b3b33b1703bb5e4f1abcbb8794e743da5d6f3bf630f2e9b6d5b54",
+ "370b47acf89ac6bdbb13c9a7336787dc41e1ad8beead32281d0609fb54968404bdf2894892590658",
+
+ "26376bcb2f23df1083cd684fe00ed3c726376bcb2f23df10",
+ "33acfb0f3d240ea6",
+ "903a1911da1e6877f23c1985a9b61786ef438e0ce1240885035ad60fc916b18e5d71a1fb9c5d1eff61db75c0076f6efb",
+ "7a4f7510f6ec0b93e2495d21a8355684d303a770ebda2e0e51ff33d72b20cb73e58e2e3de2ef6b2e12c504c0f181ba63",
+
+ "3e1f98135d027cec752f67765408a7913e1f98135d027cec",
+ "11f5f2304b28f68b",
+ "7c022f5af24f7925d323d4d0e20a2ce49272c5e764b22c806f4b6ddc406d864fe5bd1c3f45556d3eb30c8676c2f8b54a5a32423a0bd95a07",
+ "2bb4b131fa4ae0b4f0378a2cdb68556af6eee837613016d7ea936f3931f25f8b3ae351d5e9d00be665676e2400408b5db9892d95421e7f1a",
+
+ "13b9d549cd136ec7bf9e9810ef2cdcbf13b9d549cd136ec7",
+ "a82c1b1057badcc8",
+ "1fff1563bc1645b55cb23ea34a0049dfc06607150614b621dedcb07f20433402a2d869c95ac4a070c7a3da838c928a385f899c5d21ecb58f4e5cbdad98d39b8c",
+ "75f804d4a2c542a31703e23df26cc38861a0729090e6eae5672c1db8c0b09fba9b125bbca7d6c7d330b3859e6725c6d26de21c4e3af7f5ea94df3cde2349ce37",
+
+ "20320dfdad579bb57c6e4acd769dbadf20320dfdad579bb5",
+ "879201b5857ccdea",
+ "0431283cc8bb4dc7750a9d5c68578486932091632a12d0a79f2c54e3d122130881fff727050f317a40fcd1a8d13793458b99fc98254ba6a233e3d95b55cf5a3faff78809999ea4bf",
+ "85d17840eb2af5fc727027336bfd71a2b31bd14a1d9eb64f8a08bfc4f56eaa9ca7654a5ae698287869cc27324813730de4f1384e0b8cfbc472ff5470e3c5e4bd8ceb23dc2d91988c",
+
+ "23abb073a2df34cb3d1fdce6b092582c23abb073a2df34cb",
+ "7d7fbf19e8562d32",
+ "31e718fd95e6d7ca4f94763191add2674ab07c909d88c486916c16d60a048a0cf8cdb631cebec791362cd0c202eb61e166b65c1f65d0047c8aec57d3d84b9e17032442dce148e1191b06a12c284cc41e",
+ "c9a3f75ab6a7cd08a7fd53ca540aafe731d257ee1c379fadcc4cc1a06e7c12bddbeb7562c436d1da849ed072629e82a97b56d9becc25ff4f16f21c5f2a01911604f0b5c49df96cb641faee662ca8aa68",
+
+ "b5cb1504802326c73df186e3e352a20de643b0d63ee30e37",
+ "43f791134c5647ba",
+ "dcc153cef81d6f24",
+ "92538bd8af18d3ba",
+
+ "a49d7564199e97cb529d2c9d97bf2f98d35edf57ba1f7358",
+ "c2e999cb6249023c",
+ "c689aee38a301bb316da75db36f110b5",
+ "e9afaba5ec75ea1bbe65506655bb4ecb",
+
+ "1a5d4c0825072a15a8ad9dfdaeda8c048adffb85bc4fced0",
+ "7fcfa736f7548b6f",
+ "983c3edacd939406010e1bc6ff9e12320ac5008117fa8f84",
+ "d84fa24f38cf451ca2c9adc960120bd8ff9871584fe31cee",
+
+ "d98aadc76d4a3716158c32866efbb9ce834af2297379a49d",
+ "3c5220327c502b44",
+ "6174079dda53ca723ebf00a66837f8d5ce648c08acaa5ee45ffe62210ef79d3e",
+ "f5bd4d600bed77bec78409e3530ebda1d815506ed53103015b87e371ae000958",
+
+ "ef6d3e54266d978ffb0b8ce6689d803e2cd34cc802fd0252",
+ "38bae5bce06d0ad9",
+ "c4f228b537223cd01c0debb5d9d4e12ba71656618d119b2f8f0af29d23efa3a9e43c4c458a1b79a0",
+ "9e3289fb18379f55aa4e45a7e0e6df160b33b75f8627ad0954f8fdcb78cee55a4664caeda1000fe5",
+
+ "625bc19b19df83abfb2f5bec9d4f2062017525a75bc26e70",
+ "bd0cff364ff69a91",
+ "8152d2ab876c3c8201403a5a406d3feaf27319dbea6ad01e24f4d18203704b86de70da6bbb6d638e5aba3ff576b79b28",
+ "706fe7a973fac40e25b2b4499ce527078944c70e976d017b6af86a3a7a6b52943a72ba18a58000d2b61fdc3bfef2bc4a",
+
+ "b6383176046e6880a1023bf45768b5bf5119022fe054bfe5",
+ "ec13ca541c43401e",
+ "cd5a886e9af011346c4dba36a424f96a78a1ddf28aaa4188bf65451f4efaffc7179a6dd237c0ae35d9b672314e5cb032612597f7e462c6f3",
+ "b030f976f46277ee211c4a324d5c87555d1084513a1223d3b84416b52bbc28f4b77f3a9d8d0d91dc37d3dbe8af8be98f74674b02f9a38527",
+
+ "3d8cf273d343b9aedccddacb91ad86206737adc86b4a49a7",
+ "bb3a9a0c71c62ef0",
+ "1fde3991c32ce220b5b6666a9234f2fd7bd24b921829fd9cdc6eb4218be9eac9faa9c2351777349128086b6d58776bc86ff2f76ee1b3b2850a318462b8983fa1",
+ "422ce705a46bb52ad928dab6c863166d617c6fc24003633120d91918314bbf464cea7345c3c35f2042f2d6929735d74d7728f22fea618a0b9cf5b1281acb13fb",
+
+ "fbceb5cb646b925be0b92f7f6b493d5e5b16e9159732732a",
+ "2e17b3c7025ae86b",
+ "4c309bc8e1e464fdd2a2b8978645d668d455f7526bd8d7b6716a722f6a900b815c4a73cc30e788065c1dfca7bf5958a6cc5440a5ebe7f8691c20278cde95db764ff8ce8994ece89c",
+ "c02129bdf4bbbd75e71605a00b12c80db6b4e05308e916615011f09147ed915dd1bc67f27f9e027e4e13df36b55464a31c11b4d1fe3d855d89df492e1a7201b995c1ba16a8dbabee",
+
+ "9b162a0df8ad9b61c88676e3d586434570b902f12a2046e0",
+ "ebd6fefe029ad54b",
+ "f4c1c918e77355c8156f0fd778da52bff121ae5f2f44eaf4d2754946d0e10d1f18ce3a0176e69c18b7d20b6e0d0bee5eb5edfe4bd60e4d92adcd86bce72e76f94ee5cbcaa8b01cfddcea2ade575e66ac",
+ "1ff3c8709f403a8eff291aedf50c010df5c5ff64a8b205f1fce68564798897a390db16ee0d053856b75898009731da290fcc119dad987277aacef694872e880c4bb41471063fae05c89f25e4bd0cad6a",
+
+ NULL
+};
+
+static void
+xor_buf(unsigned char *dst, const unsigned char *src, size_t len)
+{
+ while (len -- > 0) {
+ *dst ++ ^= *src ++;
+ }
+}
+
+static void
+monte_carlo_DES_encrypt(const br_block_cbcenc_class *ve)
+{
+ unsigned char k1[8], k2[8], k3[8];
+ unsigned char buf[8];
+ unsigned char cipher[8];
+ int i, j;
+ br_des_gen_cbcenc_keys v_ec;
+ void *ec;
+
+ ec = &v_ec;
+ hextobin(k1, "9ec2372c86379df4");
+ hextobin(k2, "ad7ac4464f73805d");
+ hextobin(k3, "20c4f87564527c91");
+ hextobin(buf, "b624d6bd41783ab1");
+ hextobin(cipher, "eafd97b190b167fe");
+ for (i = 0; i < 400; i ++) {
+ unsigned char key[24];
+
+ memcpy(key, k1, 8);
+ memcpy(key + 8, k2, 8);
+ memcpy(key + 16, k3, 8);
+ ve->init(ec, key, sizeof key);
+ for (j = 0; j < 10000; j ++) {
+ unsigned char iv[8];
+
+ memset(iv, 0, sizeof iv);
+ ve->run(ec, iv, buf, sizeof buf);
+ switch (j) {
+ case 9997: xor_buf(k3, buf, 8); break;
+ case 9998: xor_buf(k2, buf, 8); break;
+ case 9999: xor_buf(k1, buf, 8); break;
+ }
+ }
+ printf(".");
+ fflush(stdout);
+ }
+ printf(" ");
+ fflush(stdout);
+ check_equals("MC DES encrypt", buf, cipher, sizeof buf);
+}
+
+static void
+monte_carlo_DES_decrypt(const br_block_cbcdec_class *vd)
+{
+ unsigned char k1[8], k2[8], k3[8];
+ unsigned char buf[8];
+ unsigned char plain[8];
+ int i, j;
+ br_des_gen_cbcdec_keys v_dc;
+ void *dc;
+
+ dc = &v_dc;
+ hextobin(k1, "79b63486e0ce37e0");
+ hextobin(k2, "08e65231abae3710");
+ hextobin(k3, "1f5eb69e925ef185");
+ hextobin(buf, "2783aa729432fe96");
+ hextobin(plain, "44937ca532cdbf98");
+ for (i = 0; i < 400; i ++) {
+ unsigned char key[24];
+
+ memcpy(key, k1, 8);
+ memcpy(key + 8, k2, 8);
+ memcpy(key + 16, k3, 8);
+ vd->init(dc, key, sizeof key);
+ for (j = 0; j < 10000; j ++) {
+ unsigned char iv[8];
+
+ memset(iv, 0, sizeof iv);
+ vd->run(dc, iv, buf, sizeof buf);
+ switch (j) {
+ case 9997: xor_buf(k3, buf, 8); break;
+ case 9998: xor_buf(k2, buf, 8); break;
+ case 9999: xor_buf(k1, buf, 8); break;
+ }
+ }
+ printf(".");
+ fflush(stdout);
+ }
+ printf(" ");
+ fflush(stdout);
+ check_equals("MC DES decrypt", buf, plain, sizeof buf);
+}
+
+static void
+test_DES_generic(char *name,
+ const br_block_cbcenc_class *ve,
+ const br_block_cbcdec_class *vd,
+ int with_MC, int with_CBC)
+{
+ size_t u;
+
+ printf("Test %s: ", name);
+ fflush(stdout);
+
+ if (ve->block_size != 8 || vd->block_size != 8) {
+ fprintf(stderr, "%s failed: wrong block size\n", name);
+ exit(EXIT_FAILURE);
+ }
+
+ for (u = 0; KAT_DES[u]; u += 3) {
+ unsigned char key[24];
+ unsigned char plain[8];
+ unsigned char cipher[8];
+ unsigned char buf[8];
+ unsigned char iv[8];
+ size_t key_len;
+ br_des_gen_cbcenc_keys v_ec;
+ br_des_gen_cbcdec_keys v_dc;
+ const br_block_cbcenc_class **ec;
+ const br_block_cbcdec_class **dc;
+
+ ec = &v_ec.vtable;
+ dc = &v_dc.vtable;
+ key_len = hextobin(key, KAT_DES[u]);
+ hextobin(plain, KAT_DES[u + 1]);
+ hextobin(cipher, KAT_DES[u + 2]);
+ ve->init(ec, key, key_len);
+ memcpy(buf, plain, sizeof plain);
+ memset(iv, 0, sizeof iv);
+ ve->run(ec, iv, buf, sizeof buf);
+ check_equals("KAT DES encrypt", buf, cipher, sizeof cipher);
+ vd->init(dc, key, key_len);
+ memset(iv, 0, sizeof iv);
+ vd->run(dc, iv, buf, sizeof buf);
+ check_equals("KAT DES decrypt", buf, plain, sizeof plain);
+
+ if (key_len == 8) {
+ memcpy(key + 8, key, 8);
+ memcpy(key + 16, key, 8);
+ ve->init(ec, key, 24);
+ memcpy(buf, plain, sizeof plain);
+ memset(iv, 0, sizeof iv);
+ ve->run(ec, iv, buf, sizeof buf);
+ check_equals("KAT DES->3 encrypt",
+ buf, cipher, sizeof cipher);
+ vd->init(dc, key, 24);
+ memset(iv, 0, sizeof iv);
+ vd->run(dc, iv, buf, sizeof buf);
+ check_equals("KAT DES->3 decrypt",
+ buf, plain, sizeof plain);
+ }
+ }
+
+ if (with_CBC) {
+ for (u = 0; KAT_DES_CBC[u]; u += 4) {
+ unsigned char key[24];
+ unsigned char ivref[8];
+ unsigned char plain[200];
+ unsigned char cipher[200];
+ unsigned char buf[200];
+ unsigned char iv[8];
+ size_t key_len, data_len, v;
+ br_des_gen_cbcenc_keys v_ec;
+ br_des_gen_cbcdec_keys v_dc;
+ const br_block_cbcenc_class **ec;
+ const br_block_cbcdec_class **dc;
+
+ ec = &v_ec.vtable;
+ dc = &v_dc.vtable;
+ key_len = hextobin(key, KAT_DES_CBC[u]);
+ hextobin(ivref, KAT_DES_CBC[u + 1]);
+ data_len = hextobin(plain, KAT_DES_CBC[u + 2]);
+ hextobin(cipher, KAT_DES_CBC[u + 3]);
+ ve->init(ec, key, key_len);
+
+ memcpy(buf, plain, data_len);
+ memcpy(iv, ivref, 8);
+ ve->run(ec, iv, buf, data_len);
+ check_equals("KAT CBC DES encrypt",
+ buf, cipher, data_len);
+ vd->init(dc, key, key_len);
+ memcpy(iv, ivref, 8);
+ vd->run(dc, iv, buf, data_len);
+ check_equals("KAT CBC DES decrypt",
+ buf, plain, data_len);
+
+ memcpy(buf, plain, data_len);
+ memcpy(iv, ivref, 8);
+ for (v = 0; v < data_len; v += 8) {
+ ve->run(ec, iv, buf + v, 8);
+ }
+ check_equals("KAT CBC DES encrypt (2)",
+ buf, cipher, data_len);
+ memcpy(iv, ivref, 8);
+ for (v = 0; v < data_len; v += 8) {
+ vd->run(dc, iv, buf + v, 8);
+ }
+ check_equals("KAT CBC DES decrypt (2)",
+ buf, plain, data_len);
+ }
+ }
+
+ if (with_MC) {
+ monte_carlo_DES_encrypt(ve);
+ monte_carlo_DES_decrypt(vd);
+ }
+
+ printf("done.\n");
+ fflush(stdout);
+}
+
+static void
+test_DES_tab(void)
+{
+ test_DES_generic("DES_tab",
+ &br_des_tab_cbcenc_vtable,
+ &br_des_tab_cbcdec_vtable,
+ 1, 1);
+}
+
+static void
+test_DES_ct(void)
+{
+ test_DES_generic("DES_ct",
+ &br_des_ct_cbcenc_vtable,
+ &br_des_ct_cbcdec_vtable,
+ 1, 1);
+}
+
+/*
+ * A 1024-bit RSA key, generated with OpenSSL.
+ */
+static const unsigned char RSA_N[] = {
+ 0xBF, 0xB4, 0xA6, 0x2E, 0x87, 0x3F, 0x9C, 0x8D,
+ 0xA0, 0xC4, 0x2E, 0x7B, 0x59, 0x36, 0x0F, 0xB0,
+ 0xFF, 0xE1, 0x25, 0x49, 0xE5, 0xE6, 0x36, 0xB0,
+ 0x48, 0xC2, 0x08, 0x6B, 0x77, 0xA7, 0xC0, 0x51,
+ 0x66, 0x35, 0x06, 0xA9, 0x59, 0xDF, 0x17, 0x7F,
+ 0x15, 0xF6, 0xB4, 0xE5, 0x44, 0xEE, 0x72, 0x3C,
+ 0x53, 0x11, 0x52, 0xC9, 0xC9, 0x61, 0x4F, 0x92,
+ 0x33, 0x64, 0x70, 0x43, 0x07, 0xF1, 0x3F, 0x7F,
+ 0x15, 0xAC, 0xF0, 0xC1, 0x54, 0x7D, 0x55, 0xC0,
+ 0x29, 0xDC, 0x9E, 0xCC, 0xE4, 0x1D, 0x11, 0x72,
+ 0x45, 0xF4, 0xD2, 0x70, 0xFC, 0x34, 0xB2, 0x1F,
+ 0xF3, 0xAD, 0x6A, 0xF0, 0xE5, 0x56, 0x11, 0xF8,
+ 0x0C, 0x3A, 0x8B, 0x04, 0x46, 0x7C, 0x77, 0xD9,
+ 0x41, 0x1F, 0x40, 0xBE, 0x93, 0x80, 0x9D, 0x23,
+ 0x75, 0x80, 0x12, 0x26, 0x5A, 0x72, 0x1C, 0xDD,
+ 0x47, 0xB3, 0x2A, 0x33, 0xD8, 0x19, 0x61, 0xE3
+};
+static const unsigned char RSA_E[] = {
+ 0x01, 0x00, 0x01
+};
+/* unused
+static const unsigned char RSA_D[] = {
+ 0xAE, 0x56, 0x0B, 0x56, 0x7E, 0xDA, 0x83, 0x75,
+ 0x6C, 0xC1, 0x5C, 0x00, 0x02, 0x96, 0x1E, 0x58,
+ 0xF9, 0xA9, 0xF7, 0x2E, 0x27, 0xEB, 0x5E, 0xCA,
+ 0x9B, 0xB0, 0x10, 0xD6, 0x22, 0x7F, 0xA4, 0x6E,
+ 0xA2, 0x03, 0x10, 0xE6, 0xCB, 0x7B, 0x0D, 0x34,
+ 0x1E, 0x76, 0x37, 0xF5, 0xD3, 0xE5, 0x00, 0x70,
+ 0x09, 0x9E, 0xD4, 0x69, 0xFB, 0x40, 0x0A, 0x8B,
+ 0xCB, 0x3E, 0xC8, 0xB4, 0xBC, 0xB1, 0x50, 0xEA,
+ 0x9D, 0xD9, 0x89, 0x8A, 0x98, 0x40, 0x79, 0xD1,
+ 0x07, 0x66, 0xA7, 0x90, 0x63, 0x82, 0xB1, 0xE0,
+ 0x24, 0xD0, 0x89, 0x6A, 0xEC, 0xC5, 0xF3, 0x21,
+ 0x7D, 0xB8, 0xA5, 0x45, 0x3A, 0x3B, 0x34, 0x42,
+ 0xC2, 0x82, 0x3C, 0x8D, 0xFA, 0x5D, 0xA0, 0xA8,
+ 0x24, 0xC8, 0x40, 0x22, 0x19, 0xCB, 0xB5, 0x85,
+ 0x67, 0x69, 0x60, 0xE4, 0xD0, 0x7E, 0xA3, 0x3B,
+ 0xF7, 0x70, 0x50, 0xC9, 0x5C, 0x97, 0x29, 0x49
+};
+*/
+static const unsigned char RSA_P[] = {
+ 0xF2, 0xE7, 0x6F, 0x66, 0x2E, 0xC4, 0x03, 0xD4,
+ 0x89, 0x24, 0xCC, 0xE1, 0xCD, 0x3F, 0x01, 0x82,
+ 0xC1, 0xFB, 0xAF, 0x44, 0xFA, 0xCC, 0x0E, 0xAA,
+ 0x9D, 0x74, 0xA9, 0x65, 0xEF, 0xED, 0x4C, 0x87,
+ 0xF0, 0xB3, 0xC6, 0xEA, 0x61, 0x85, 0xDE, 0x4E,
+ 0x66, 0xB2, 0x5A, 0x9F, 0x7A, 0x41, 0xC5, 0x66,
+ 0x57, 0xDF, 0x88, 0xF0, 0xB5, 0xF2, 0xC7, 0x7E,
+ 0xE6, 0x55, 0x21, 0x96, 0x83, 0xD8, 0xAB, 0x57
+};
+static const unsigned char RSA_Q[] = {
+ 0xCA, 0x0A, 0x92, 0xBF, 0x58, 0xB0, 0x2E, 0xF6,
+ 0x66, 0x50, 0xB1, 0x48, 0x29, 0x42, 0x86, 0x6C,
+ 0x98, 0x06, 0x7E, 0xB8, 0xB5, 0x4F, 0xFB, 0xC4,
+ 0xF3, 0xC3, 0x36, 0x91, 0x07, 0xB6, 0xDB, 0xE9,
+ 0x56, 0x3C, 0x51, 0x7D, 0xB5, 0xEC, 0x0A, 0xA9,
+ 0x7C, 0x66, 0xF9, 0xD8, 0x25, 0xDE, 0xD2, 0x94,
+ 0x5A, 0x58, 0xF1, 0x93, 0xE4, 0xF0, 0x5F, 0x27,
+ 0xBD, 0x83, 0xC7, 0xCA, 0x48, 0x6A, 0xB2, 0x55
+};
+static const unsigned char RSA_DP[] = {
+ 0xAF, 0x97, 0xBE, 0x60, 0x0F, 0xCE, 0x83, 0x36,
+ 0x51, 0x2D, 0xD9, 0x2E, 0x22, 0x41, 0x39, 0xC6,
+ 0x5C, 0x94, 0xA4, 0xCF, 0x28, 0xBD, 0xFA, 0x9C,
+ 0x3B, 0xD6, 0xE9, 0xDE, 0x56, 0xE3, 0x24, 0x3F,
+ 0xE1, 0x31, 0x14, 0xCA, 0xBA, 0x55, 0x1B, 0xAF,
+ 0x71, 0x6D, 0xDD, 0x35, 0x0C, 0x1C, 0x1F, 0xA7,
+ 0x2C, 0x3E, 0xDB, 0xAF, 0xA6, 0xD8, 0x2A, 0x7F,
+ 0x01, 0xE2, 0xE8, 0xB4, 0xF5, 0xFA, 0xDB, 0x61
+};
+static const unsigned char RSA_DQ[] = {
+ 0x29, 0xC0, 0x4B, 0x98, 0xFD, 0x13, 0xD3, 0x70,
+ 0x99, 0xAE, 0x1D, 0x24, 0x83, 0x5A, 0x3A, 0xFB,
+ 0x1F, 0xE3, 0x5F, 0xB6, 0x7D, 0xC9, 0x5C, 0x86,
+ 0xD3, 0xB4, 0xC8, 0x86, 0xE9, 0xE8, 0x30, 0xC3,
+ 0xA4, 0x4D, 0x6C, 0xAD, 0xA4, 0xB5, 0x75, 0x72,
+ 0x96, 0xC1, 0x94, 0xE9, 0xC4, 0xD1, 0xAA, 0x04,
+ 0x7C, 0x33, 0x1B, 0x20, 0xEB, 0xD3, 0x7C, 0x66,
+ 0x72, 0xF4, 0x53, 0x8A, 0x0A, 0xB2, 0xF9, 0xCD
+};
+static const unsigned char RSA_IQ[] = {
+ 0xE8, 0xEB, 0x04, 0x79, 0xA5, 0xC1, 0x79, 0xDE,
+ 0xD5, 0x49, 0xA1, 0x0B, 0x48, 0xB9, 0x0E, 0x55,
+ 0x74, 0x2C, 0x54, 0xEE, 0xA8, 0xB0, 0x01, 0xC2,
+ 0xD2, 0x3C, 0x3E, 0x47, 0x3A, 0x7C, 0xC8, 0x3D,
+ 0x2E, 0x33, 0x54, 0x4D, 0x40, 0x29, 0x41, 0x74,
+ 0xBA, 0xE1, 0x93, 0x09, 0xEC, 0xE0, 0x1B, 0x4D,
+ 0x1F, 0x2A, 0xCA, 0x4A, 0x0B, 0x5F, 0xE6, 0xBE,
+ 0x59, 0x0A, 0xC4, 0xC9, 0xD9, 0x82, 0xAC, 0xE1
+};
+
+static const br_rsa_public_key RSA_PK = {
+ (void *)RSA_N, sizeof RSA_N,
+ (void *)RSA_E, sizeof RSA_E
+};
+
+static const br_rsa_private_key RSA_SK = {
+ 1024,
+ (void *)RSA_P, sizeof RSA_P,
+ (void *)RSA_Q, sizeof RSA_Q,
+ (void *)RSA_DP, sizeof RSA_DP,
+ (void *)RSA_DQ, sizeof RSA_DQ,
+ (void *)RSA_IQ, sizeof RSA_IQ
+};
+
+static void
+test_RSA_core(char *name, br_rsa_public fpub, br_rsa_private fpriv)
+{
+ unsigned char t1[128], t2[128], t3[128];
+
+ printf("Test %s: ", name);
+ fflush(stdout);
+
+ /*
+ * A KAT test (computed with OpenSSL).
+ */
+ hextobin(t1, "45A3DC6A106BCD3BD0E48FB579643AA3FF801E5903E80AA9B43A695A8E7F454E93FA208B69995FF7A6D5617C2FEB8E546375A664977A48931842AAE796B5A0D64393DCA35F3490FC157F5BD83B9D58C2F7926E6AE648A2BD96CAB8FCCD3D35BB11424AD47D973FF6D69CA774841AEC45DFAE99CCF79893E7047FDE6CB00AA76D");
+ hextobin(t2, "0001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF003021300906052B0E03021A05000414A94A8FE5CCB19BA61C4C0873D391E987982FBBD3");
+ memcpy(t3, t1, sizeof t1);
+ if (!fpub(t3, sizeof t3, &RSA_PK)) {
+ fprintf(stderr, "RSA public operation failed\n");
+ exit(EXIT_FAILURE);
+ }
+ check_equals("KAT RSA pub", t2, t3, sizeof t2);
+ if (!fpriv(t3, &RSA_SK)) {
+ fprintf(stderr, "RSA private operation failed\n");
+ exit(EXIT_FAILURE);
+ }
+ check_equals("KAT RSA priv", t1, t3, sizeof t1);
+
+ printf("done.\n");
+ fflush(stdout);
+}
+
+static void
+test_RSA_i31(void)
+{
+ test_RSA_core("RSA i31 core", &br_rsa_i31_public, &br_rsa_i31_private);
+ /* FIXME
+ test_RSA_sign("RSA i31 sign",
+ &br_rsa_i31_pkcs1_vrfy, &br_rsa_i31_pkcs1_sign);
+ */
+}
+
+static void
+test_RSA_i32(void)
+{
+ test_RSA_core("RSA i32 core", &br_rsa_i32_public, &br_rsa_i32_private);
+ /* FIXME
+ test_RSA_sign("RSA i32 sign",
+ &br_rsa_i32_pkcs1_vrfy, &br_rsa_i32_pkcs1_sign);
+ */
+}
+
+#if 0
+static void
+test_RSA_signatures(void)
+{
+ uint32_t n[40], e[2], p[20], q[20], dp[20], dq[20], iq[20], x[40];
+ unsigned char hv[20], sig[128];
+ unsigned char ref[128], tmp[128];
+ br_sha1_context hc;
+
+ printf("Test RSA signatures: ");
+ fflush(stdout);
+
+ /*
+ * Decode RSA key elements.
+ */
+ br_int_decode(n, sizeof n / sizeof n[0], RSA_N, sizeof RSA_N);
+ br_int_decode(e, sizeof e / sizeof e[0], RSA_E, sizeof RSA_E);
+ br_int_decode(p, sizeof p / sizeof p[0], RSA_P, sizeof RSA_P);
+ br_int_decode(q, sizeof q / sizeof q[0], RSA_Q, sizeof RSA_Q);
+ br_int_decode(dp, sizeof dp / sizeof dp[0], RSA_DP, sizeof RSA_DP);
+ br_int_decode(dq, sizeof dq / sizeof dq[0], RSA_DQ, sizeof RSA_DQ);
+ br_int_decode(iq, sizeof iq / sizeof iq[0], RSA_IQ, sizeof RSA_IQ);
+
+ /*
+ * Decode reference signature (computed with OpenSSL).
+ */
+ hextobin(ref, "45A3DC6A106BCD3BD0E48FB579643AA3FF801E5903E80AA9B43A695A8E7F454E93FA208B69995FF7A6D5617C2FEB8E546375A664977A48931842AAE796B5A0D64393DCA35F3490FC157F5BD83B9D58C2F7926E6AE648A2BD96CAB8FCCD3D35BB11424AD47D973FF6D69CA774841AEC45DFAE99CCF79893E7047FDE6CB00AA76D");
+
+ /*
+ * Recompute signature. Since PKCS#1 v1.5 signatures are
+ * deterministic, we should get the same as the reference signature.
+ */
+ br_sha1_init(&hc);
+ br_sha1_update(&hc, "test", 4);
+ br_sha1_out(&hc, hv);
+ if (!br_rsa_sign(sig, sizeof sig, p, q, dp, dq, iq, br_sha1_ID, hv)) {
+ fprintf(stderr, "RSA-1024/SHA-1 sig generate failed\n");
+ exit(EXIT_FAILURE);
+ }
+ check_equals("KAT RSA-sign 1", sig, ref, sizeof sig);
+
+ /*
+ * Verify signature.
+ */
+ if (!br_rsa_verify(sig, sizeof sig, n, e, br_sha1_ID, hv)) {
+ fprintf(stderr, "RSA-1024/SHA-1 sig verify failed\n");
+ exit(EXIT_FAILURE);
+ }
+ hv[5] ^= 0x01;
+ if (br_rsa_verify(sig, sizeof sig, n, e, br_sha1_ID, hv)) {
+ fprintf(stderr, "RSA-1024/SHA-1 sig verify should have failed\n");
+ exit(EXIT_FAILURE);
+ }
+ hv[5] ^= 0x01;
+
+ /*
+ * Generate a signature with the alternate encoding (no NULL) and
+ * verify it.
+ */
+ hextobin(tmp, "0001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00301F300706052B0E03021A0414A94A8FE5CCB19BA61C4C0873D391E987982FBBD3");
+ br_int_decode(x, sizeof x / sizeof x[0], tmp, sizeof tmp);
+ x[0] = n[0];
+ br_rsa_private_core(x, p, q, dp, dq, iq);
+ br_int_encode(sig, sizeof sig, x);
+ if (!br_rsa_verify(sig, sizeof sig, n, e, br_sha1_ID, hv)) {
+ fprintf(stderr, "RSA-1024/SHA-1 sig verify (alt) failed\n");
+ exit(EXIT_FAILURE);
+ }
+ hv[5] ^= 0x01;
+ if (br_rsa_verify(sig, sizeof sig, n, e, br_sha1_ID, hv)) {
+ fprintf(stderr, "RSA-1024/SHA-1 sig verify (alt) should have failed\n");
+ exit(EXIT_FAILURE);
+ }
+ hv[5] ^= 0x01;
+
+ printf("done.\n");
+ fflush(stdout);
+}
+#endif
+
+/*
+ * From: http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf
+ */
+static const char *const KAT_GHASH[] = {
+
+ "66e94bd4ef8a2c3b884cfa59ca342b2e",
+ "",
+ "",
+ "00000000000000000000000000000000",
+
+ "66e94bd4ef8a2c3b884cfa59ca342b2e",
+ "",
+ "0388dace60b6a392f328c2b971b2fe78",
+ "f38cbb1ad69223dcc3457ae5b6b0f885",
+
+ "b83b533708bf535d0aa6e52980d53b78",
+ "",
+ "42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f5985",
+ "7f1b32b81b820d02614f8895ac1d4eac",
+
+ "b83b533708bf535d0aa6e52980d53b78",
+ "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+ "42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091",
+ "698e57f70e6ecc7fd9463b7260a9ae5f",
+
+ "b83b533708bf535d0aa6e52980d53b78",
+ "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+ "61353b4c2806934a777ff51fa22a4755699b2a714fcdc6f83766e5f97b6c742373806900e49f24b22b097544d4896b424989b5e1ebac0f07c23f4598",
+ "df586bb4c249b92cb6922877e444d37b",
+
+ "b83b533708bf535d0aa6e52980d53b78",
+ "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+ "8ce24998625615b603a033aca13fb894be9112a5c3a211a8ba262a3cca7e2ca701e4a9a4fba43c90ccdcb281d48c7c6fd62875d2aca417034c34aee5",
+ "1c5afe9760d3932f3c9a878aac3dc3de",
+
+ "aae06992acbf52a3e8f4a96ec9300bd7",
+ "",
+ "98e7247c07f0fe411c267e4384b0f600",
+ "e2c63f0ac44ad0e02efa05ab6743d4ce",
+
+ "466923ec9ae682214f2c082badb39249",
+ "",
+ "3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c7d773d00c144c525ac619d18c84a3f4718e2448b2fe324d9ccda2710acade256",
+ "51110d40f6c8fff0eb1ae33445a889f0",
+
+ "466923ec9ae682214f2c082badb39249",
+ "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+ "3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c7d773d00c144c525ac619d18c84a3f4718e2448b2fe324d9ccda2710",
+ "ed2ce3062e4a8ec06db8b4c490e8a268",
+
+ "466923ec9ae682214f2c082badb39249",
+ "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+ "0f10f599ae14a154ed24b36e25324db8c566632ef2bbb34f8347280fc4507057fddc29df9a471f75c66541d4d4dad1c9e93a19a58e8b473fa0f062f7",
+ "1e6a133806607858ee80eaf237064089",
+
+ "466923ec9ae682214f2c082badb39249",
+ "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+ "d27e88681ce3243c4830165a8fdcf9ff1de9a1d8e6b447ef6ef7b79828666e4581e79012af34ddd9e2f037589b292db3e67c036745fa22e7e9b7373b",
+ "82567fb0b4cc371801eadec005968e94",
+
+ "dc95c078a2408989ad48a21492842087",
+ "",
+ "cea7403d4d606b6e074ec5d3baf39d18",
+ "83de425c5edc5d498f382c441041ca92",
+
+ "acbef20579b4b8ebce889bac8732dad7",
+ "",
+ "522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662898015ad",
+ "4db870d37cb75fcb46097c36230d1612",
+
+ "acbef20579b4b8ebce889bac8732dad7",
+ "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+ "522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662",
+ "8bd0c4d8aacd391e67cca447e8c38f65",
+
+ "acbef20579b4b8ebce889bac8732dad7",
+ "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+ "c3762df1ca787d32ae47c13bf19844cbaf1ae14d0b976afac52ff7d79bba9de0feb582d33934a4f0954cc2363bc73f7862ac430e64abe499f47c9b1f",
+ "75a34288b8c68f811c52b2e9a2f97f63",
+
+ "acbef20579b4b8ebce889bac8732dad7",
+ "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+ "5a8def2f0c9e53f1f75d7853659e2a20eeb2b22aafde6419a058ab4f6f746bf40fc0c3b780f244452da3ebf1c5d82cdea2418997200ef82e44ae7e3f",
+ "d5ffcf6fc5ac4d69722187421a7f170b",
+
+ NULL,
+};
+
+static void
+test_GHASH(char *name, br_ghash gh)
+{
+ size_t u;
+
+ printf("Test %s: ", name);
+ fflush(stdout);
+
+ for (u = 0; KAT_GHASH[u]; u += 4) {
+ unsigned char h[16];
+ unsigned char a[100];
+ size_t a_len;
+ unsigned char c[100];
+ size_t c_len;
+ unsigned char p[16];
+ unsigned char y[16];
+ unsigned char ref[16];
+
+ hextobin(h, KAT_GHASH[u]);
+ a_len = hextobin(a, KAT_GHASH[u + 1]);
+ c_len = hextobin(c, KAT_GHASH[u + 2]);
+ hextobin(ref, KAT_GHASH[u + 3]);
+ memset(y, 0, sizeof y);
+ gh(y, h, a, a_len);
+ gh(y, h, c, c_len);
+ memset(p, 0, sizeof p);
+ br_enc32be(p + 4, (uint32_t)a_len << 3);
+ br_enc32be(p + 12, (uint32_t)c_len << 3);
+ gh(y, h, p, sizeof p);
+ check_equals("KAT GHASH", y, ref, sizeof ref);
+ }
+
+ printf("done.\n");
+ fflush(stdout);
+}
+
+static void
+test_GHASH_ctmul(void)
+{
+ test_GHASH("GHASH_ctmul", br_ghash_ctmul);
+}
+
+static void
+test_GHASH_ctmul32(void)
+{
+ test_GHASH("GHASH_ctmul32", br_ghash_ctmul32);
+}
+
+static void
+test_GHASH_ctmul64(void)
+{
+ test_GHASH("GHASH_ctmul64", br_ghash_ctmul64);
+}
+
+static void
+test_EC_inner(const char *sk, const char *sU,
+ const br_ec_impl *impl, int curve)
+{
+ unsigned char bk[70];
+ unsigned char eG[150], eU[150];
+ uint32_t n[22], n0i;
+ size_t klen, ulen, nlen;
+ const br_ec_curve_def *cd;
+ br_hmac_drbg_context rng;
+ int i;
+
+ klen = hextobin(bk, sk);
+ ulen = hextobin(eU, sU);
+ switch (curve) {
+ case BR_EC_secp256r1:
+ cd = &br_secp256r1;
+ break;
+ case BR_EC_secp384r1:
+ cd = &br_secp384r1;
+ break;
+ case BR_EC_secp521r1:
+ cd = &br_secp521r1;
+ break;
+ default:
+ fprintf(stderr, "Unknown curve: %d\n", curve);
+ exit(EXIT_FAILURE);
+ break;
+ }
+ if (ulen != cd->generator_len) {
+ fprintf(stderr, "KAT vector wrong (%lu / %lu)\n",
+ (unsigned long)ulen,
+ (unsigned long)cd->generator_len);
+ }
+ memcpy(eG, cd->generator, ulen);
+ if (impl->mul(eG, ulen, bk, klen, curve) != 1) {
+ fprintf(stderr, "KAT multiplication failed\n");
+ exit(EXIT_FAILURE);
+ }
+ if (memcmp(eG, eU, ulen) != 0) {
+ fprintf(stderr, "KAT mul: mismatch\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ * Test the two-point-mul function. We want to test the basic
+ * functionality, and the following special cases:
+ * x = y
+ * x + y = curve order
+ */
+ nlen = cd->order_len;
+ br_i31_decode(n, cd->order, nlen);
+ n0i = br_i31_ninv31(n[1]);
+ br_hmac_drbg_init(&rng, &br_sha256_vtable, "seed for EC", 11);
+ for (i = 0; i < 10; i ++) {
+ unsigned char ba[80], bb[80], bx[80], by[80], bz[80];
+ uint32_t a[22], b[22], x[22], y[22], z[22], t1[22], t2[22];
+ uint32_t r;
+ unsigned char eA[160], eB[160], eC[160], eD[160];
+
+ /*
+ * Generate random a and b, and compute A = a*G and B = b*G.
+ */
+ br_hmac_drbg_generate(&rng, ba, sizeof ba);
+ br_i31_decode_reduce(a, ba, sizeof ba, n);
+ br_i31_encode(ba, nlen, a);
+ br_hmac_drbg_generate(&rng, bb, sizeof bb);
+ br_i31_decode_reduce(b, bb, sizeof bb, n);
+ br_i31_encode(bb, nlen, b);
+ memcpy(eA, cd->generator, ulen);
+ impl->mul(eA, ulen, ba, nlen, cd->curve);
+ memcpy(eB, cd->generator, ulen);
+ impl->mul(eB, ulen, bb, nlen, cd->curve);
+
+ /*
+ * Generate random x and y (modulo n).
+ */
+ br_hmac_drbg_generate(&rng, bx, sizeof bx);
+ br_i31_decode_reduce(x, bx, sizeof bx, n);
+ br_i31_encode(bx, nlen, x);
+ br_hmac_drbg_generate(&rng, by, sizeof by);
+ br_i31_decode_reduce(y, by, sizeof by, n);
+ br_i31_encode(by, nlen, y);
+
+ /*
+ * Compute z = a*x + b*y (mod n).
+ */
+ memcpy(t1, x, sizeof x);
+ br_i31_to_monty(t1, n);
+ br_i31_montymul(z, a, t1, n, n0i);
+ memcpy(t1, y, sizeof y);
+ br_i31_to_monty(t1, n);
+ br_i31_montymul(t2, b, t1, n, n0i);
+ r = br_i31_add(z, t2, 1);
+ r |= br_i31_sub(z, n, 0) ^ 1;
+ br_i31_sub(z, n, r);
+ br_i31_encode(bz, nlen, z);
+
+ /*
+ * Compute C = x*A + y*B with muladd(), and also
+ * D = z*G with mul(). The two points must match.
+ */
+ memcpy(eC, eA, ulen);
+ if (impl->muladd(eC, eB, ulen,
+ bx, nlen, by, nlen, cd->curve) != 1)
+ {
+ fprintf(stderr, "muladd() failed (1)\n");
+ exit(EXIT_FAILURE);
+ }
+ memcpy(eD, cd->generator, ulen);
+ if (impl->mul(eD, ulen, bz, nlen, cd->curve) != 1) {
+ fprintf(stderr, "mul() failed (1)\n");
+ exit(EXIT_FAILURE);
+ }
+ if (memcmp(eC, eD, nlen) != 0) {
+ fprintf(stderr, "mul() / muladd() mismatch\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ * Check with x*A = y*B. We do so by setting b = x and y = a.
+ */
+ memcpy(b, x, sizeof x);
+ br_i31_encode(bb, nlen, b);
+ memcpy(eB, cd->generator, ulen);
+ impl->mul(eB, ulen, bb, nlen, cd->curve);
+ memcpy(y, a, sizeof a);
+ br_i31_encode(by, nlen, y);
+
+ memcpy(t1, x, sizeof x);
+ br_i31_to_monty(t1, n);
+ br_i31_montymul(z, a, t1, n, n0i);
+ memcpy(t1, y, sizeof y);
+ br_i31_to_monty(t1, n);
+ br_i31_montymul(t2, b, t1, n, n0i);
+ r = br_i31_add(z, t2, 1);
+ r |= br_i31_sub(z, n, 0) ^ 1;
+ br_i31_sub(z, n, r);
+ br_i31_encode(bz, nlen, z);
+
+ memcpy(eC, eA, ulen);
+ if (impl->muladd(eC, eB, ulen,
+ bx, nlen, by, nlen, cd->curve) != 1)
+ {
+ fprintf(stderr, "muladd() failed (2)\n");
+ exit(EXIT_FAILURE);
+ }
+ memcpy(eD, cd->generator, ulen);
+ if (impl->mul(eD, ulen, bz, nlen, cd->curve) != 1) {
+ fprintf(stderr, "mul() failed (2)\n");
+ exit(EXIT_FAILURE);
+ }
+ if (memcmp(eC, eD, nlen) != 0) {
+ fprintf(stderr,
+ "mul() / muladd() mismatch (x*A=y*B)\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ * Check with x*A + y*B = 0. At that point, b = x, so we
+ * just need to set y = -a (mod n).
+ */
+ memcpy(y, n, sizeof n);
+ br_i31_sub(y, a, 1);
+ br_i31_encode(by, nlen, y);
+ memcpy(eC, eA, ulen);
+ if (impl->muladd(eC, eB, ulen,
+ bx, nlen, by, nlen, cd->curve) != 0)
+ {
+ fprintf(stderr, "muladd() should have failed\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ printf(".");
+ fflush(stdout);
+}
+
+static void
+test_EC_KAT(const char *name, const br_ec_impl *impl, uint32_t curve_mask)
+{
+
+ printf("Test %s: ", name);
+ fflush(stdout);
+
+ if (curve_mask & ((uint32_t)1 << BR_EC_secp256r1)) {
+ test_EC_inner(
+ "C9AFA9D845BA75166B5C215767B1D6934E50C3DB36E89B127B8A622B120F6721",
+ "0460FED4BA255A9D31C961EB74C6356D68C049B8923B61FA6CE669622E60F29FB67903FE1008B8BC99A41AE9E95628BC64F2F1B20C2D7E9F5177A3C294D4462299",
+ impl, BR_EC_secp256r1);
+ }
+ if (curve_mask & ((uint32_t)1 << BR_EC_secp384r1)) {
+ test_EC_inner(
+ "6B9D3DAD2E1B8C1C05B19875B6659F4DE23C3B667BF297BA9AA47740787137D896D5724E4C70A825F872C9EA60D2EDF5",
+ "04EC3A4E415B4E19A4568618029F427FA5DA9A8BC4AE92E02E06AAE5286B300C64DEF8F0EA9055866064A254515480BC138015D9B72D7D57244EA8EF9AC0C621896708A59367F9DFB9F54CA84B3F1C9DB1288B231C3AE0D4FE7344FD2533264720",
+ impl, BR_EC_secp384r1);
+ }
+ if (curve_mask & ((uint32_t)1 << BR_EC_secp521r1)) {
+ test_EC_inner(
+ "00FAD06DAA62BA3B25D2FB40133DA757205DE67F5BB0018FEE8C86E1B68C7E75CAA896EB32F1F47C70855836A6D16FCC1466F6D8FBEC67DB89EC0C08B0E996B83538",
+ "0401894550D0785932E00EAA23B694F213F8C3121F86DC97A04E5A7167DB4E5BCD371123D46E45DB6B5D5370A7F20FB633155D38FFA16D2BD761DCAC474B9A2F5023A400493101C962CD4D2FDDF782285E64584139C2F91B47F87FF82354D6630F746A28A0DB25741B5B34A828008B22ACC23F924FAAFBD4D33F81EA66956DFEAA2BFDFCF5",
+ impl, BR_EC_secp521r1);
+ }
+
+ printf(" done.\n");
+ fflush(stdout);
+}
+
+static void
+test_EC_prime_i31(void)
+{
+ test_EC_KAT("EC_prime_i31", &br_ec_prime_i31,
+ (uint32_t)1 << BR_EC_secp256r1
+ | (uint32_t)1 << BR_EC_secp384r1
+ | (uint32_t)1 << BR_EC_secp521r1);
+}
+
+static const unsigned char EC_P256_PUB_POINT[] = {
+ 0x04, 0x60, 0xFE, 0xD4, 0xBA, 0x25, 0x5A, 0x9D,
+ 0x31, 0xC9, 0x61, 0xEB, 0x74, 0xC6, 0x35, 0x6D,
+ 0x68, 0xC0, 0x49, 0xB8, 0x92, 0x3B, 0x61, 0xFA,
+ 0x6C, 0xE6, 0x69, 0x62, 0x2E, 0x60, 0xF2, 0x9F,
+ 0xB6, 0x79, 0x03, 0xFE, 0x10, 0x08, 0xB8, 0xBC,
+ 0x99, 0xA4, 0x1A, 0xE9, 0xE9, 0x56, 0x28, 0xBC,
+ 0x64, 0xF2, 0xF1, 0xB2, 0x0C, 0x2D, 0x7E, 0x9F,
+ 0x51, 0x77, 0xA3, 0xC2, 0x94, 0xD4, 0x46, 0x22,
+ 0x99
+};
+
+static const unsigned char EC_P256_PRIV_X[] = {
+ 0xC9, 0xAF, 0xA9, 0xD8, 0x45, 0xBA, 0x75, 0x16,
+ 0x6B, 0x5C, 0x21, 0x57, 0x67, 0xB1, 0xD6, 0x93,
+ 0x4E, 0x50, 0xC3, 0xDB, 0x36, 0xE8, 0x9B, 0x12,
+ 0x7B, 0x8A, 0x62, 0x2B, 0x12, 0x0F, 0x67, 0x21
+};
+
+static const br_ec_public_key EC_P256_PUB = {
+ BR_EC_secp256r1,
+ (unsigned char *)EC_P256_PUB_POINT, sizeof EC_P256_PUB_POINT
+};
+
+static const br_ec_private_key EC_P256_PRIV = {
+ BR_EC_secp256r1,
+ (unsigned char *)EC_P256_PRIV_X, sizeof EC_P256_PRIV_X
+};
+
+static const unsigned char EC_P384_PUB_POINT[] = {
+ 0x04, 0xEC, 0x3A, 0x4E, 0x41, 0x5B, 0x4E, 0x19,
+ 0xA4, 0x56, 0x86, 0x18, 0x02, 0x9F, 0x42, 0x7F,
+ 0xA5, 0xDA, 0x9A, 0x8B, 0xC4, 0xAE, 0x92, 0xE0,
+ 0x2E, 0x06, 0xAA, 0xE5, 0x28, 0x6B, 0x30, 0x0C,
+ 0x64, 0xDE, 0xF8, 0xF0, 0xEA, 0x90, 0x55, 0x86,
+ 0x60, 0x64, 0xA2, 0x54, 0x51, 0x54, 0x80, 0xBC,
+ 0x13, 0x80, 0x15, 0xD9, 0xB7, 0x2D, 0x7D, 0x57,
+ 0x24, 0x4E, 0xA8, 0xEF, 0x9A, 0xC0, 0xC6, 0x21,
+ 0x89, 0x67, 0x08, 0xA5, 0x93, 0x67, 0xF9, 0xDF,
+ 0xB9, 0xF5, 0x4C, 0xA8, 0x4B, 0x3F, 0x1C, 0x9D,
+ 0xB1, 0x28, 0x8B, 0x23, 0x1C, 0x3A, 0xE0, 0xD4,
+ 0xFE, 0x73, 0x44, 0xFD, 0x25, 0x33, 0x26, 0x47,
+ 0x20
+};
+
+static const unsigned char EC_P384_PRIV_X[] = {
+ 0x6B, 0x9D, 0x3D, 0xAD, 0x2E, 0x1B, 0x8C, 0x1C,
+ 0x05, 0xB1, 0x98, 0x75, 0xB6, 0x65, 0x9F, 0x4D,
+ 0xE2, 0x3C, 0x3B, 0x66, 0x7B, 0xF2, 0x97, 0xBA,
+ 0x9A, 0xA4, 0x77, 0x40, 0x78, 0x71, 0x37, 0xD8,
+ 0x96, 0xD5, 0x72, 0x4E, 0x4C, 0x70, 0xA8, 0x25,
+ 0xF8, 0x72, 0xC9, 0xEA, 0x60, 0xD2, 0xED, 0xF5
+};
+
+static const br_ec_public_key EC_P384_PUB = {
+ BR_EC_secp384r1,
+ (unsigned char *)EC_P384_PUB_POINT, sizeof EC_P384_PUB_POINT
+};
+
+static const br_ec_private_key EC_P384_PRIV = {
+ BR_EC_secp384r1,
+ (unsigned char *)EC_P384_PRIV_X, sizeof EC_P384_PRIV_X
+};
+
+static const unsigned char EC_P521_PUB_POINT[] = {
+ 0x04, 0x01, 0x89, 0x45, 0x50, 0xD0, 0x78, 0x59,
+ 0x32, 0xE0, 0x0E, 0xAA, 0x23, 0xB6, 0x94, 0xF2,
+ 0x13, 0xF8, 0xC3, 0x12, 0x1F, 0x86, 0xDC, 0x97,
+ 0xA0, 0x4E, 0x5A, 0x71, 0x67, 0xDB, 0x4E, 0x5B,
+ 0xCD, 0x37, 0x11, 0x23, 0xD4, 0x6E, 0x45, 0xDB,
+ 0x6B, 0x5D, 0x53, 0x70, 0xA7, 0xF2, 0x0F, 0xB6,
+ 0x33, 0x15, 0x5D, 0x38, 0xFF, 0xA1, 0x6D, 0x2B,
+ 0xD7, 0x61, 0xDC, 0xAC, 0x47, 0x4B, 0x9A, 0x2F,
+ 0x50, 0x23, 0xA4, 0x00, 0x49, 0x31, 0x01, 0xC9,
+ 0x62, 0xCD, 0x4D, 0x2F, 0xDD, 0xF7, 0x82, 0x28,
+ 0x5E, 0x64, 0x58, 0x41, 0x39, 0xC2, 0xF9, 0x1B,
+ 0x47, 0xF8, 0x7F, 0xF8, 0x23, 0x54, 0xD6, 0x63,
+ 0x0F, 0x74, 0x6A, 0x28, 0xA0, 0xDB, 0x25, 0x74,
+ 0x1B, 0x5B, 0x34, 0xA8, 0x28, 0x00, 0x8B, 0x22,
+ 0xAC, 0xC2, 0x3F, 0x92, 0x4F, 0xAA, 0xFB, 0xD4,
+ 0xD3, 0x3F, 0x81, 0xEA, 0x66, 0x95, 0x6D, 0xFE,
+ 0xAA, 0x2B, 0xFD, 0xFC, 0xF5
+};
+
+static const unsigned char EC_P521_PRIV_X[] = {
+ 0x00, 0xFA, 0xD0, 0x6D, 0xAA, 0x62, 0xBA, 0x3B,
+ 0x25, 0xD2, 0xFB, 0x40, 0x13, 0x3D, 0xA7, 0x57,
+ 0x20, 0x5D, 0xE6, 0x7F, 0x5B, 0xB0, 0x01, 0x8F,
+ 0xEE, 0x8C, 0x86, 0xE1, 0xB6, 0x8C, 0x7E, 0x75,
+ 0xCA, 0xA8, 0x96, 0xEB, 0x32, 0xF1, 0xF4, 0x7C,
+ 0x70, 0x85, 0x58, 0x36, 0xA6, 0xD1, 0x6F, 0xCC,
+ 0x14, 0x66, 0xF6, 0xD8, 0xFB, 0xEC, 0x67, 0xDB,
+ 0x89, 0xEC, 0x0C, 0x08, 0xB0, 0xE9, 0x96, 0xB8,
+ 0x35, 0x38
+};
+
+static const br_ec_public_key EC_P521_PUB = {
+ BR_EC_secp521r1,
+ (unsigned char *)EC_P521_PUB_POINT, sizeof EC_P521_PUB_POINT
+};
+
+static const br_ec_private_key EC_P521_PRIV = {
+ BR_EC_secp521r1,
+ (unsigned char *)EC_P521_PRIV_X, sizeof EC_P521_PRIV_X
+};
+
+typedef struct {
+ const br_ec_public_key *pub;
+ const br_ec_private_key *priv;
+ const br_hash_class *hf;
+ const char *msg;
+ const char *sk;
+ const char *sraw;
+ const char *sasn1;
+} ecdsa_kat_vector;
+
+const ecdsa_kat_vector ECDSA_KAT[] = {
+
+ /* Test vectors for P-256, from RFC 6979. */
+ {
+ &EC_P256_PUB,
+ &EC_P256_PRIV,
+ &br_sha1_vtable, "sample",
+ "882905F1227FD620FBF2ABF21244F0BA83D0DC3A9103DBBEE43A1FB858109DB4",
+ "61340C88C3AAEBEB4F6D667F672CA9759A6CCAA9FA8811313039EE4A35471D326D7F147DAC089441BB2E2FE8F7A3FA264B9C475098FDCF6E00D7C996E1B8B7EB",
+ "3044022061340C88C3AAEBEB4F6D667F672CA9759A6CCAA9FA8811313039EE4A35471D3202206D7F147DAC089441BB2E2FE8F7A3FA264B9C475098FDCF6E00D7C996E1B8B7EB"
+ },
+ {
+ &EC_P256_PUB,
+ &EC_P256_PRIV,
+ &br_sha224_vtable, "sample",
+ "103F90EE9DC52E5E7FB5132B7033C63066D194321491862059967C715985D473",
+ "53B2FFF5D1752B2C689DF257C04C40A587FABABB3F6FC2702F1343AF7CA9AA3FB9AFB64FDC03DC1A131C7D2386D11E349F070AA432A4ACC918BEA988BF75C74C",
+ "3045022053B2FFF5D1752B2C689DF257C04C40A587FABABB3F6FC2702F1343AF7CA9AA3F022100B9AFB64FDC03DC1A131C7D2386D11E349F070AA432A4ACC918BEA988BF75C74C"
+ },
+ {
+ &EC_P256_PUB,
+ &EC_P256_PRIV,
+ &br_sha256_vtable, "sample",
+ "A6E3C57DD01ABE90086538398355DD4C3B17AA873382B0F24D6129493D8AAD60",
+ "EFD48B2AACB6A8FD1140DD9CD45E81D69D2C877B56AAF991C34D0EA84EAF3716F7CB1C942D657C41D436C7A1B6E29F65F3E900DBB9AFF4064DC4AB2F843ACDA8",
+ "3046022100EFD48B2AACB6A8FD1140DD9CD45E81D69D2C877B56AAF991C34D0EA84EAF3716022100F7CB1C942D657C41D436C7A1B6E29F65F3E900DBB9AFF4064DC4AB2F843ACDA8"
+ },
+ {
+ &EC_P256_PUB,
+ &EC_P256_PRIV,
+ &br_sha384_vtable, "sample",
+ "09F634B188CEFD98E7EC88B1AA9852D734D0BC272F7D2A47DECC6EBEB375AAD4",
+ "0EAFEA039B20E9B42309FB1D89E213057CBF973DC0CFC8F129EDDDC800EF77194861F0491E6998B9455193E34E7B0D284DDD7149A74B95B9261F13ABDE940954",
+ "304402200EAFEA039B20E9B42309FB1D89E213057CBF973DC0CFC8F129EDDDC800EF771902204861F0491E6998B9455193E34E7B0D284DDD7149A74B95B9261F13ABDE940954"
+ },
+ {
+ &EC_P256_PUB,
+ &EC_P256_PRIV,
+ &br_sha512_vtable, "sample",
+ "5FA81C63109BADB88C1F367B47DA606DA28CAD69AA22C4FE6AD7DF73A7173AA5",
+ "8496A60B5E9B47C825488827E0495B0E3FA109EC4568FD3F8D1097678EB97F002362AB1ADBE2B8ADF9CB9EDAB740EA6049C028114F2460F96554F61FAE3302FE",
+ "30450221008496A60B5E9B47C825488827E0495B0E3FA109EC4568FD3F8D1097678EB97F0002202362AB1ADBE2B8ADF9CB9EDAB740EA6049C028114F2460F96554F61FAE3302FE"
+ },
+ {
+ &EC_P256_PUB,
+ &EC_P256_PRIV,
+ &br_sha1_vtable, "test",
+ "8C9520267C55D6B980DF741E56B4ADEE114D84FBFA2E62137954164028632A2E",
+ "0CBCC86FD6ABD1D99E703E1EC50069EE5C0B4BA4B9AC60E409E8EC5910D81A8901B9D7B73DFAA60D5651EC4591A0136F87653E0FD780C3B1BC872FFDEAE479B1",
+ "304402200CBCC86FD6ABD1D99E703E1EC50069EE5C0B4BA4B9AC60E409E8EC5910D81A89022001B9D7B73DFAA60D5651EC4591A0136F87653E0FD780C3B1BC872FFDEAE479B1"
+ },
+ {
+ &EC_P256_PUB,
+ &EC_P256_PRIV,
+ &br_sha224_vtable, "test",
+ "669F4426F2688B8BE0DB3A6BD1989BDAEFFF84B649EEB84F3DD26080F667FAA7",
+ "C37EDB6F0AE79D47C3C27E962FA269BB4F441770357E114EE511F662EC34A692C820053A05791E521FCAAD6042D40AEA1D6B1A540138558F47D0719800E18F2D",
+ "3046022100C37EDB6F0AE79D47C3C27E962FA269BB4F441770357E114EE511F662EC34A692022100C820053A05791E521FCAAD6042D40AEA1D6B1A540138558F47D0719800E18F2D"
+ },
+ {
+ &EC_P256_PUB,
+ &EC_P256_PRIV,
+ &br_sha256_vtable, "test",
+ "D16B6AE827F17175E040871A1C7EC3500192C4C92677336EC2537ACAEE0008E0",
+ "F1ABB023518351CD71D881567B1EA663ED3EFCF6C5132B354F28D3B0B7D38367019F4113742A2B14BD25926B49C649155F267E60D3814B4C0CC84250E46F0083",
+ "3045022100F1ABB023518351CD71D881567B1EA663ED3EFCF6C5132B354F28D3B0B7D383670220019F4113742A2B14BD25926B49C649155F267E60D3814B4C0CC84250E46F0083"
+ },
+ {
+ &EC_P256_PUB,
+ &EC_P256_PRIV,
+ &br_sha384_vtable, "test",
+ "16AEFFA357260B04B1DD199693960740066C1A8F3E8EDD79070AA914D361B3B8",
+ "83910E8B48BB0C74244EBDF7F07A1C5413D61472BD941EF3920E623FBCCEBEB68DDBEC54CF8CD5874883841D712142A56A8D0F218F5003CB0296B6B509619F2C",
+ "304602210083910E8B48BB0C74244EBDF7F07A1C5413D61472BD941EF3920E623FBCCEBEB60221008DDBEC54CF8CD5874883841D712142A56A8D0F218F5003CB0296B6B509619F2C"
+ },
+ {
+ &EC_P256_PUB,
+ &EC_P256_PRIV,
+ &br_sha512_vtable, "test",
+ "6915D11632ACA3C40D5D51C08DAF9C555933819548784480E93499000D9F0B7F",
+ "461D93F31B6540894788FD206C07CFA0CC35F46FA3C91816FFF1040AD1581A0439AF9F15DE0DB8D97E72719C74820D304CE5226E32DEDAE67519E840D1194E55",
+ "30440220461D93F31B6540894788FD206C07CFA0CC35F46FA3C91816FFF1040AD1581A04022039AF9F15DE0DB8D97E72719C74820D304CE5226E32DEDAE67519E840D1194E55"
+ },
+
+ /* Test vectors for P-384, from RFC 6979. */
+ {
+ &EC_P384_PUB,
+ &EC_P384_PRIV,
+ &br_sha1_vtable, "sample",
+ "4471EF7518BB2C7C20F62EAE1C387AD0C5E8E470995DB4ACF694466E6AB096630F29E5938D25106C3C340045A2DB01A7",
+ "EC748D839243D6FBEF4FC5C4859A7DFFD7F3ABDDF72014540C16D73309834FA37B9BA002899F6FDA3A4A9386790D4EB2A3BCFA947BEEF4732BF247AC17F71676CB31A847B9FF0CBC9C9ED4C1A5B3FACF26F49CA031D4857570CCB5CA4424A443",
+ "3066023100EC748D839243D6FBEF4FC5C4859A7DFFD7F3ABDDF72014540C16D73309834FA37B9BA002899F6FDA3A4A9386790D4EB2023100A3BCFA947BEEF4732BF247AC17F71676CB31A847B9FF0CBC9C9ED4C1A5B3FACF26F49CA031D4857570CCB5CA4424A443"
+ },
+
+ {
+ &EC_P384_PUB,
+ &EC_P384_PRIV,
+ &br_sha224_vtable, "sample",
+ "A4E4D2F0E729EB786B31FC20AD5D849E304450E0AE8E3E341134A5C1AFA03CAB8083EE4E3C45B06A5899EA56C51B5879",
+ "42356E76B55A6D9B4631C865445DBE54E056D3B3431766D0509244793C3F9366450F76EE3DE43F5A125333A6BE0601229DA0C81787064021E78DF658F2FBB0B042BF304665DB721F077A4298B095E4834C082C03D83028EFBF93A3C23940CA8D",
+ "3065023042356E76B55A6D9B4631C865445DBE54E056D3B3431766D0509244793C3F9366450F76EE3DE43F5A125333A6BE0601220231009DA0C81787064021E78DF658F2FBB0B042BF304665DB721F077A4298B095E4834C082C03D83028EFBF93A3C23940CA8D"
+ },
+ {
+ &EC_P384_PUB,
+ &EC_P384_PRIV,
+ &br_sha256_vtable, "sample",
+ "180AE9F9AEC5438A44BC159A1FCB277C7BE54FA20E7CF404B490650A8ACC414E375572342863C899F9F2EDF9747A9B60",
+ "21B13D1E013C7FA1392D03C5F99AF8B30C570C6F98D4EA8E354B63A21D3DAA33BDE1E888E63355D92FA2B3C36D8FB2CDF3AA443FB107745BF4BD77CB3891674632068A10CA67E3D45DB2266FA7D1FEEBEFDC63ECCD1AC42EC0CB8668A4FA0AB0",
+ "3065023021B13D1E013C7FA1392D03C5F99AF8B30C570C6F98D4EA8E354B63A21D3DAA33BDE1E888E63355D92FA2B3C36D8FB2CD023100F3AA443FB107745BF4BD77CB3891674632068A10CA67E3D45DB2266FA7D1FEEBEFDC63ECCD1AC42EC0CB8668A4FA0AB0"
+ },
+ {
+ &EC_P384_PUB,
+ &EC_P384_PRIV,
+ &br_sha384_vtable, "sample",
+ "94ED910D1A099DAD3254E9242AE85ABDE4BA15168EAF0CA87A555FD56D10FBCA2907E3E83BA95368623B8C4686915CF9",
+ "94EDBB92A5ECB8AAD4736E56C691916B3F88140666CE9FA73D64C4EA95AD133C81A648152E44ACF96E36DD1E80FABE4699EF4AEB15F178CEA1FE40DB2603138F130E740A19624526203B6351D0A3A94FA329C145786E679E7B82C71A38628AC8",
+ "306602310094EDBB92A5ECB8AAD4736E56C691916B3F88140666CE9FA73D64C4EA95AD133C81A648152E44ACF96E36DD1E80FABE4602310099EF4AEB15F178CEA1FE40DB2603138F130E740A19624526203B6351D0A3A94FA329C145786E679E7B82C71A38628AC8"
+ },
+ {
+ &EC_P384_PUB,
+ &EC_P384_PRIV,
+ &br_sha512_vtable, "sample",
+ "92FC3C7183A883E24216D1141F1A8976C5B0DD797DFA597E3D7B32198BD35331A4E966532593A52980D0E3AAA5E10EC3",
+ "ED0959D5880AB2D869AE7F6C2915C6D60F96507F9CB3E047C0046861DA4A799CFE30F35CC900056D7C99CD7882433709512C8CCEEE3890A84058CE1E22DBC2198F42323CE8ACA9135329F03C068E5112DC7CC3EF3446DEFCEB01A45C2667FDD5",
+ "3065023100ED0959D5880AB2D869AE7F6C2915C6D60F96507F9CB3E047C0046861DA4A799CFE30F35CC900056D7C99CD78824337090230512C8CCEEE3890A84058CE1E22DBC2198F42323CE8ACA9135329F03C068E5112DC7CC3EF3446DEFCEB01A45C2667FDD5"
+ },
+ {
+ &EC_P384_PUB,
+ &EC_P384_PRIV,
+ &br_sha1_vtable, "test",
+ "66CC2C8F4D303FC962E5FF6A27BD79F84EC812DDAE58CF5243B64A4AD8094D47EC3727F3A3C186C15054492E30698497",
+ "4BC35D3A50EF4E30576F58CD96CE6BF638025EE624004A1F7789A8B8E43D0678ACD9D29876DAF46638645F7F404B11C7D5A6326C494ED3FF614703878961C0FDE7B2C278F9A65FD8C4B7186201A2991695BA1C84541327E966FA7B50F7382282",
+ "306502304BC35D3A50EF4E30576F58CD96CE6BF638025EE624004A1F7789A8B8E43D0678ACD9D29876DAF46638645F7F404B11C7023100D5A6326C494ED3FF614703878961C0FDE7B2C278F9A65FD8C4B7186201A2991695BA1C84541327E966FA7B50F7382282"
+ },
+ {
+ &EC_P384_PUB,
+ &EC_P384_PRIV,
+ &br_sha224_vtable, "test",
+ "18FA39DB95AA5F561F30FA3591DC59C0FA3653A80DAFFA0B48D1A4C6DFCBFF6E3D33BE4DC5EB8886A8ECD093F2935726",
+ "E8C9D0B6EA72A0E7837FEA1D14A1A9557F29FAA45D3E7EE888FC5BF954B5E62464A9A817C47FF78B8C11066B24080E7207041D4A7A0379AC7232FF72E6F77B6DDB8F09B16CCE0EC3286B2BD43FA8C6141C53EA5ABEF0D8231077A04540A96B66",
+ "3065023100E8C9D0B6EA72A0E7837FEA1D14A1A9557F29FAA45D3E7EE888FC5BF954B5E62464A9A817C47FF78B8C11066B24080E72023007041D4A7A0379AC7232FF72E6F77B6DDB8F09B16CCE0EC3286B2BD43FA8C6141C53EA5ABEF0D8231077A04540A96B66"
+ },
+ {
+ &EC_P384_PUB,
+ &EC_P384_PRIV,
+ &br_sha256_vtable, "test",
+ "0CFAC37587532347DC3389FDC98286BBA8C73807285B184C83E62E26C401C0FAA48DD070BA79921A3457ABFF2D630AD7",
+ "6D6DEFAC9AB64DABAFE36C6BF510352A4CC27001263638E5B16D9BB51D451559F918EEDAF2293BE5B475CC8F0188636B2D46F3BECBCC523D5F1A1256BF0C9B024D879BA9E838144C8BA6BAEB4B53B47D51AB373F9845C0514EEFB14024787265",
+ "306402306D6DEFAC9AB64DABAFE36C6BF510352A4CC27001263638E5B16D9BB51D451559F918EEDAF2293BE5B475CC8F0188636B02302D46F3BECBCC523D5F1A1256BF0C9B024D879BA9E838144C8BA6BAEB4B53B47D51AB373F9845C0514EEFB14024787265"
+ },
+ {
+ &EC_P384_PUB,
+ &EC_P384_PRIV,
+ &br_sha384_vtable, "test",
+ "015EE46A5BF88773ED9123A5AB0807962D193719503C527B031B4C2D225092ADA71F4A459BC0DA98ADB95837DB8312EA",
+ "8203B63D3C853E8D77227FB377BCF7B7B772E97892A80F36AB775D509D7A5FEB0542A7F0812998DA8F1DD3CA3CF023DBDDD0760448D42D8A43AF45AF836FCE4DE8BE06B485E9B61B827C2F13173923E06A739F040649A667BF3B828246BAA5A5",
+ "30660231008203B63D3C853E8D77227FB377BCF7B7B772E97892A80F36AB775D509D7A5FEB0542A7F0812998DA8F1DD3CA3CF023DB023100DDD0760448D42D8A43AF45AF836FCE4DE8BE06B485E9B61B827C2F13173923E06A739F040649A667BF3B828246BAA5A5"
+ },
+ {
+ &EC_P384_PUB,
+ &EC_P384_PRIV,
+ &br_sha512_vtable, "test",
+ "3780C4F67CB15518B6ACAE34C9F83568D2E12E47DEAB6C50A4E4EE5319D1E8CE0E2CC8A136036DC4B9C00E6888F66B6C",
+ "A0D5D090C9980FAF3C2CE57B7AE951D31977DD11C775D314AF55F76C676447D06FB6495CD21B4B6E340FC236584FB277976984E59B4C77B0E8E4460DCA3D9F20E07B9BB1F63BEEFAF576F6B2E8B224634A2092CD3792E0159AD9CEE37659C736",
+ "3066023100A0D5D090C9980FAF3C2CE57B7AE951D31977DD11C775D314AF55F76C676447D06FB6495CD21B4B6E340FC236584FB277023100976984E59B4C77B0E8E4460DCA3D9F20E07B9BB1F63BEEFAF576F6B2E8B224634A2092CD3792E0159AD9CEE37659C736"
+ },
+
+ /* Test vectors for P-521, from RFC 6979. */
+ {
+ &EC_P521_PUB,
+ &EC_P521_PRIV,
+ &br_sha1_vtable, "sample",
+ "0089C071B419E1C2820962321787258469511958E80582E95D8378E0C2CCDB3CB42BEDE42F50E3FA3C71F5A76724281D31D9C89F0F91FC1BE4918DB1C03A5838D0F9",
+ "00343B6EC45728975EA5CBA6659BBB6062A5FF89EEA58BE3C80B619F322C87910FE092F7D45BB0F8EEE01ED3F20BABEC079D202AE677B243AB40B5431D497C55D75D00E7B0E675A9B24413D448B8CC119D2BF7B2D2DF032741C096634D6D65D0DBE3D5694625FB9E8104D3B842C1B0E2D0B98BEA19341E8676AEF66AE4EBA3D5475D5D16",
+ "3081870241343B6EC45728975EA5CBA6659BBB6062A5FF89EEA58BE3C80B619F322C87910FE092F7D45BB0F8EEE01ED3F20BABEC079D202AE677B243AB40B5431D497C55D75D024200E7B0E675A9B24413D448B8CC119D2BF7B2D2DF032741C096634D6D65D0DBE3D5694625FB9E8104D3B842C1B0E2D0B98BEA19341E8676AEF66AE4EBA3D5475D5D16"
+ },
+ {
+ &EC_P521_PUB,
+ &EC_P521_PRIV,
+ &br_sha224_vtable, "sample",
+ "0121415EC2CD7726330A61F7F3FA5DE14BE9436019C4DB8CB4041F3B54CF31BE0493EE3F427FB906393D895A19C9523F3A1D54BB8702BD4AA9C99DAB2597B92113F3",
+ "01776331CFCDF927D666E032E00CF776187BC9FDD8E69D0DABB4109FFE1B5E2A30715F4CC923A4A5E94D2503E9ACFED92857B7F31D7152E0F8C00C15FF3D87E2ED2E0050CB5265417FE2320BBB5A122B8E1A32BD699089851128E360E620A30C7E17BA41A666AF126CE100E5799B153B60528D5300D08489CA9178FB610A2006C254B41F",
+ "308187024201776331CFCDF927D666E032E00CF776187BC9FDD8E69D0DABB4109FFE1B5E2A30715F4CC923A4A5E94D2503E9ACFED92857B7F31D7152E0F8C00C15FF3D87E2ED2E024150CB5265417FE2320BBB5A122B8E1A32BD699089851128E360E620A30C7E17BA41A666AF126CE100E5799B153B60528D5300D08489CA9178FB610A2006C254B41F"
+ },
+ {
+ &EC_P521_PUB,
+ &EC_P521_PRIV,
+ &br_sha256_vtable, "sample",
+ "00EDF38AFCAAECAB4383358B34D67C9F2216C8382AAEA44A3DAD5FDC9C32575761793FEF24EB0FC276DFC4F6E3EC476752F043CF01415387470BCBD8678ED2C7E1A0",
+ "01511BB4D675114FE266FC4372B87682BAECC01D3CC62CF2303C92B3526012659D16876E25C7C1E57648F23B73564D67F61C6F14D527D54972810421E7D87589E1A7004A171143A83163D6DF460AAF61522695F207A58B95C0644D87E52AA1A347916E4F7A72930B1BC06DBE22CE3F58264AFD23704CBB63B29B931F7DE6C9D949A7ECFC",
+ "308187024201511BB4D675114FE266FC4372B87682BAECC01D3CC62CF2303C92B3526012659D16876E25C7C1E57648F23B73564D67F61C6F14D527D54972810421E7D87589E1A702414A171143A83163D6DF460AAF61522695F207A58B95C0644D87E52AA1A347916E4F7A72930B1BC06DBE22CE3F58264AFD23704CBB63B29B931F7DE6C9D949A7ECFC"
+ },
+ {
+ &EC_P521_PUB,
+ &EC_P521_PRIV,
+ &br_sha384_vtable, "sample",
+ "01546A108BC23A15D6F21872F7DED661FA8431DDBD922D0DCDB77CC878C8553FFAD064C95A920A750AC9137E527390D2D92F153E66196966EA554D9ADFCB109C4211",
+ "01EA842A0E17D2DE4F92C15315C63DDF72685C18195C2BB95E572B9C5136CA4B4B576AD712A52BE9730627D16054BA40CC0B8D3FF035B12AE75168397F5D50C6745101F21A3CEE066E1961025FB048BD5FE2B7924D0CD797BABE0A83B66F1E35EEAF5FDE143FA85DC394A7DEE766523393784484BDF3E00114A1C857CDE1AA203DB65D61",
+ "308188024201EA842A0E17D2DE4F92C15315C63DDF72685C18195C2BB95E572B9C5136CA4B4B576AD712A52BE9730627D16054BA40CC0B8D3FF035B12AE75168397F5D50C67451024201F21A3CEE066E1961025FB048BD5FE2B7924D0CD797BABE0A83B66F1E35EEAF5FDE143FA85DC394A7DEE766523393784484BDF3E00114A1C857CDE1AA203DB65D61"
+ },
+ {
+ &EC_P521_PUB,
+ &EC_P521_PRIV,
+ &br_sha512_vtable, "sample",
+ "01DAE2EA071F8110DC26882D4D5EAE0621A3256FC8847FB9022E2B7D28E6F10198B1574FDD03A9053C08A1854A168AA5A57470EC97DD5CE090124EF52A2F7ECBFFD3",
+ "00C328FAFCBD79DD77850370C46325D987CB525569FB63C5D3BC53950E6D4C5F174E25A1EE9017B5D450606ADD152B534931D7D4E8455CC91F9B15BF05EC36E377FA00617CCE7CF5064806C467F678D3B4080D6F1CC50AF26CA209417308281B68AF282623EAA63E5B5C0723D8B8C37FF0777B1A20F8CCB1DCCC43997F1EE0E44DA4A67A",
+ "308187024200C328FAFCBD79DD77850370C46325D987CB525569FB63C5D3BC53950E6D4C5F174E25A1EE9017B5D450606ADD152B534931D7D4E8455CC91F9B15BF05EC36E377FA0241617CCE7CF5064806C467F678D3B4080D6F1CC50AF26CA209417308281B68AF282623EAA63E5B5C0723D8B8C37FF0777B1A20F8CCB1DCCC43997F1EE0E44DA4A67A"
+ },
+ {
+ &EC_P521_PUB,
+ &EC_P521_PRIV,
+ &br_sha1_vtable, "test",
+ "00BB9F2BF4FE1038CCF4DABD7139A56F6FD8BB1386561BD3C6A4FC818B20DF5DDBA80795A947107A1AB9D12DAA615B1ADE4F7A9DC05E8E6311150F47F5C57CE8B222",
+ "013BAD9F29ABE20DE37EBEB823C252CA0F63361284015A3BF430A46AAA80B87B0693F0694BD88AFE4E661FC33B094CD3B7963BED5A727ED8BD6A3A202ABE009D036701E9BB81FF7944CA409AD138DBBEE228E1AFCC0C890FC78EC8604639CB0DBDC90F717A99EAD9D272855D00162EE9527567DD6A92CBD629805C0445282BBC916797FF",
+ "3081880242013BAD9F29ABE20DE37EBEB823C252CA0F63361284015A3BF430A46AAA80B87B0693F0694BD88AFE4E661FC33B094CD3B7963BED5A727ED8BD6A3A202ABE009D0367024201E9BB81FF7944CA409AD138DBBEE228E1AFCC0C890FC78EC8604639CB0DBDC90F717A99EAD9D272855D00162EE9527567DD6A92CBD629805C0445282BBC916797FF"
+ },
+ {
+ &EC_P521_PUB,
+ &EC_P521_PRIV,
+ &br_sha224_vtable, "test",
+ "0040D09FCF3C8A5F62CF4FB223CBBB2B9937F6B0577C27020A99602C25A01136987E452988781484EDBBCF1C47E554E7FC901BC3085E5206D9F619CFF07E73D6F706",
+ "01C7ED902E123E6815546065A2C4AF977B22AA8EADDB68B2C1110E7EA44D42086BFE4A34B67DDC0E17E96536E358219B23A706C6A6E16BA77B65E1C595D43CAE17FB0177336676304FCB343CE028B38E7B4FBA76C1C1B277DA18CAD2A8478B2A9A9F5BEC0F3BA04F35DB3E4263569EC6AADE8C92746E4C82F8299AE1B8F1739F8FD519A4",
+ "308188024201C7ED902E123E6815546065A2C4AF977B22AA8EADDB68B2C1110E7EA44D42086BFE4A34B67DDC0E17E96536E358219B23A706C6A6E16BA77B65E1C595D43CAE17FB02420177336676304FCB343CE028B38E7B4FBA76C1C1B277DA18CAD2A8478B2A9A9F5BEC0F3BA04F35DB3E4263569EC6AADE8C92746E4C82F8299AE1B8F1739F8FD519A4"
+ },
+ {
+ &EC_P521_PUB,
+ &EC_P521_PRIV,
+ &br_sha256_vtable, "test",
+ "001DE74955EFAABC4C4F17F8E84D881D1310B5392D7700275F82F145C61E843841AF09035BF7A6210F5A431A6A9E81C9323354A9E69135D44EBD2FCAA7731B909258",
+ "000E871C4A14F993C6C7369501900C4BC1E9C7B0B4BA44E04868B30B41D8071042EB28C4C250411D0CE08CD197E4188EA4876F279F90B3D8D74A3C76E6F1E4656AA800CD52DBAA33B063C3A6CD8058A1FB0A46A4754B034FCC644766CA14DA8CA5CA9FDE00E88C1AD60CCBA759025299079D7A427EC3CC5B619BFBC828E7769BCD694E86",
+ "30818702410E871C4A14F993C6C7369501900C4BC1E9C7B0B4BA44E04868B30B41D8071042EB28C4C250411D0CE08CD197E4188EA4876F279F90B3D8D74A3C76E6F1E4656AA8024200CD52DBAA33B063C3A6CD8058A1FB0A46A4754B034FCC644766CA14DA8CA5CA9FDE00E88C1AD60CCBA759025299079D7A427EC3CC5B619BFBC828E7769BCD694E86"
+ },
+ {
+ &EC_P521_PUB,
+ &EC_P521_PRIV,
+ &br_sha384_vtable, "test",
+ "01F1FC4A349A7DA9A9E116BFDD055DC08E78252FF8E23AC276AC88B1770AE0B5DCEB1ED14A4916B769A523CE1E90BA22846AF11DF8B300C38818F713DADD85DE0C88",
+ "014BEE21A18B6D8B3C93FAB08D43E739707953244FDBE924FA926D76669E7AC8C89DF62ED8975C2D8397A65A49DCC09F6B0AC62272741924D479354D74FF6075578C0133330865C067A0EAF72362A65E2D7BC4E461E8C8995C3B6226A21BD1AA78F0ED94FE536A0DCA35534F0CD1510C41525D163FE9D74D134881E35141ED5E8E95B979",
+ "3081880242014BEE21A18B6D8B3C93FAB08D43E739707953244FDBE924FA926D76669E7AC8C89DF62ED8975C2D8397A65A49DCC09F6B0AC62272741924D479354D74FF6075578C02420133330865C067A0EAF72362A65E2D7BC4E461E8C8995C3B6226A21BD1AA78F0ED94FE536A0DCA35534F0CD1510C41525D163FE9D74D134881E35141ED5E8E95B979"
+ },
+ {
+ &EC_P521_PUB,
+ &EC_P521_PRIV,
+ &br_sha512_vtable, "test",
+ "016200813020EC986863BEDFC1B121F605C1215645018AEA1A7B215A564DE9EB1B38A67AA1128B80CE391C4FB71187654AAA3431027BFC7F395766CA988C964DC56D",
+ "013E99020ABF5CEE7525D16B69B229652AB6BDF2AFFCAEF38773B4B7D08725F10CDB93482FDCC54EDCEE91ECA4166B2A7C6265EF0CE2BD7051B7CEF945BABD47EE6D01FBD0013C674AA79CB39849527916CE301C66EA7CE8B80682786AD60F98F7E78A19CA69EFF5C57400E3B3A0AD66CE0978214D13BAF4E9AC60752F7B155E2DE4DCE3",
+ "3081880242013E99020ABF5CEE7525D16B69B229652AB6BDF2AFFCAEF38773B4B7D08725F10CDB93482FDCC54EDCEE91ECA4166B2A7C6265EF0CE2BD7051B7CEF945BABD47EE6D024201FBD0013C674AA79CB39849527916CE301C66EA7CE8B80682786AD60F98F7E78A19CA69EFF5C57400E3B3A0AD66CE0978214D13BAF4E9AC60752F7B155E2DE4DCE3"
+ },
+
+ /* Terminator for list of test vectors. */
+ {
+ 0, 0, 0, 0, 0, 0, 0
+ }
+};
+
+static void
+test_ECDSA_KAT(br_ecdsa_sign sign, br_ecdsa_vrfy vrfy, int asn1)
+{
+ size_t u;
+
+ for (u = 0;; u ++) {
+ const ecdsa_kat_vector *kv;
+ unsigned char hash[64];
+ size_t hash_len;
+ unsigned char sig[150], sig2[150];
+ size_t sig_len, sig2_len;
+ br_hash_compat_context hc;
+
+ kv = &ECDSA_KAT[u];
+ if (kv->pub == 0) {
+ break;
+ }
+ kv->hf->init(&hc.vtable);
+ kv->hf->update(&hc.vtable, kv->msg, strlen(kv->msg));
+ kv->hf->out(&hc.vtable, hash);
+ hash_len = (kv->hf->desc >> BR_HASHDESC_OUT_OFF)
+ & BR_HASHDESC_OUT_MASK;
+ if (asn1) {
+ sig_len = hextobin(sig, kv->sasn1);
+ } else {
+ sig_len = hextobin(sig, kv->sraw);
+ }
+
+ if (vrfy(&br_ec_prime_i31, hash, hash_len,
+ kv->pub, sig, sig_len) != 1)
+ {
+ fprintf(stderr, "ECDSA KAT verify failed (1)\n");
+ exit(EXIT_FAILURE);
+ }
+ hash[0] ^= 0x80;
+ if (vrfy(&br_ec_prime_i31, hash, hash_len,
+ kv->pub, sig, sig_len) != 0)
+ {
+ fprintf(stderr, "ECDSA KAT verify shoud have failed\n");
+ exit(EXIT_FAILURE);
+ }
+ hash[0] ^= 0x80;
+ if (vrfy(&br_ec_prime_i31, hash, hash_len,
+ kv->pub, sig, sig_len) != 1)
+ {
+ fprintf(stderr, "ECDSA KAT verify failed (2)\n");
+ exit(EXIT_FAILURE);
+ }
+
+ sig2_len = sign(&br_ec_prime_i31, kv->hf, hash, kv->priv, sig2);
+ if (sig2_len == 0) {
+ fprintf(stderr, "ECDSA KAT sign failed\n");
+ exit(EXIT_FAILURE);
+ }
+ if (sig2_len != sig_len || memcmp(sig, sig2, sig_len) != 0) {
+ fprintf(stderr, "ECDSA KAT wrong signature value\n");
+ exit(EXIT_FAILURE);
+ }
+
+ printf(".");
+ fflush(stdout);
+ }
+}
+
+static void
+test_ECDSA_i31(void)
+{
+ printf("Test ECDSA/i31: ");
+ fflush(stdout);
+ printf("[raw]");
+ fflush(stdout);
+ test_ECDSA_KAT(&br_ecdsa_i31_sign_raw, &br_ecdsa_i31_vrfy_raw, 0);
+ printf(" [asn1]");
+ fflush(stdout);
+ test_ECDSA_KAT(&br_ecdsa_i31_sign_asn1, &br_ecdsa_i31_vrfy_asn1, 1);
+ printf(" done.\n");
+ fflush(stdout);
+}
+
+static int
+eq_name(const char *s1, const char *s2)
+{
+ for (;;) {
+ int c1, c2;
+
+ for (;;) {
+ c1 = *s1 ++;
+ if (c1 >= 'A' && c1 <= 'Z') {
+ c1 += 'a' - 'A';
+ } else {
+ switch (c1) {
+ case '-': case '_': case '.': case ' ':
+ continue;
+ }
+ }
+ break;
+ }
+ for (;;) {
+ c2 = *s2 ++;
+ if (c2 >= 'A' && c2 <= 'Z') {
+ c2 += 'a' - 'A';
+ } else {
+ switch (c2) {
+ case '-': case '_': case '.': case ' ':
+ continue;
+ }
+ }
+ break;
+ }
+ if (c1 != c2) {
+ return 0;
+ }
+ if (c1 == 0) {
+ return 1;
+ }
+ }
+}
+
+#define STU(x) { &test_ ## x, #x }
+
+static const struct {
+ void (*fn)(void);
+ char *name;
+} tfns[] = {
+ STU(MD5),
+ STU(SHA1),
+ STU(SHA224),
+ STU(SHA256),
+ STU(SHA384),
+ STU(SHA512),
+ STU(MD5_SHA1),
+ STU(multihash),
+ STU(HMAC),
+ STU(HMAC_DRBG),
+ STU(PRF),
+ STU(AES_big),
+ STU(AES_small),
+ STU(AES_ct),
+ STU(AES_ct64),
+ STU(DES_tab),
+ STU(DES_ct),
+ STU(RSA_i31),
+ STU(RSA_i32),
+ STU(GHASH_ctmul),
+ STU(GHASH_ctmul32),
+ STU(GHASH_ctmul64),
+ STU(EC_prime_i31),
+ /* STU(EC_prime_i32), */
+ STU(ECDSA_i31),
+ { 0, 0 }
+};
+
+int
+main(int argc, char *argv[])
+{
+ size_t u;
+
+ if (argc <= 1) {
+ printf("usage: testcrypto all | name...\n");
+ printf("individual test names:\n");
+ for (u = 0; tfns[u].name; u ++) {
+ printf(" %s\n", tfns[u].name);
+ }
+ } else {
+ for (u = 0; tfns[u].name; u ++) {
+ int i;
+
+ for (i = 1; i < argc; i ++) {
+ if (eq_name(argv[i], tfns[u].name)
+ || eq_name(argv[i], "all"))
+ {
+ tfns[u].fn();
+ break;
+ }
+ }
+ }
+ }
+ return 0;
+}
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <time.h>
+
+#include <gmp.h>
+
+#include "bearssl.h"
+#include "inner.h"
+
+/*
+ * Pointers to implementations.
+ */
+typedef struct {
+ uint32_t word_size;
+ void (*zero)(uint32_t *x, uint32_t bit_len);
+ void (*decode)(uint32_t *x, const void *src, size_t len);
+ uint32_t (*decode_mod)(uint32_t *x,
+ const void *src, size_t len, const uint32_t *m);
+ void (*reduce)(uint32_t *x, const uint32_t *a, const uint32_t *m);
+ void (*decode_reduce)(uint32_t *x,
+ const void *src, size_t len, const uint32_t *m);
+ void (*encode)(void *dst, size_t len, const uint32_t *x);
+ uint32_t (*add)(uint32_t *a, const uint32_t *b, uint32_t ctl);
+ uint32_t (*sub)(uint32_t *a, const uint32_t *b, uint32_t ctl);
+ uint32_t (*ninv)(uint32_t x);
+ void (*montymul)(uint32_t *d, const uint32_t *x, const uint32_t *y,
+ const uint32_t *m, uint32_t m0i);
+ void (*to_monty)(uint32_t *x, const uint32_t *m);
+ void (*from_monty)(uint32_t *x, const uint32_t *m, uint32_t m0i);
+ void (*modpow)(uint32_t *x, const unsigned char *e, size_t elen,
+ const uint32_t *m, uint32_t m0i, uint32_t *t1, uint32_t *t2);
+} int_impl;
+
+static const int_impl i31_impl = {
+ 31,
+ &br_i31_zero,
+ &br_i31_decode,
+ &br_i31_decode_mod,
+ &br_i31_reduce,
+ &br_i31_decode_reduce,
+ &br_i31_encode,
+ &br_i31_add,
+ &br_i31_sub,
+ &br_i31_ninv31,
+ &br_i31_montymul,
+ &br_i31_to_monty,
+ &br_i31_from_monty,
+ &br_i31_modpow
+};
+static const int_impl i32_impl = {
+ 32,
+ &br_i32_zero,
+ &br_i32_decode,
+ &br_i32_decode_mod,
+ &br_i32_reduce,
+ &br_i32_decode_reduce,
+ &br_i32_encode,
+ &br_i32_add,
+ &br_i32_sub,
+ &br_i32_ninv32,
+ &br_i32_montymul,
+ &br_i32_to_monty,
+ &br_i32_from_monty,
+ &br_i32_modpow
+};
+
+static const int_impl *impl;
+
+static gmp_randstate_t RNG;
+
+/*
+ * Get a random prime of length 'size' bits. This function also guarantees
+ * that x-1 is not a multiple of 65537.
+ */
+static void
+rand_prime(mpz_t x, int size)
+{
+ for (;;) {
+ mpz_urandomb(x, RNG, size - 1);
+ mpz_setbit(x, 0);
+ mpz_setbit(x, size - 1);
+ if (mpz_probab_prime_p(x, 50)) {
+ mpz_sub_ui(x, x, 1);
+ if (mpz_divisible_ui_p(x, 65537)) {
+ continue;
+ }
+ mpz_add_ui(x, x, 1);
+ return;
+ }
+ }
+}
+
+/*
+ * Print out a GMP integer (for debug).
+ */
+static void
+print_z(mpz_t z)
+{
+ unsigned char zb[1000];
+ size_t zlen, k;
+
+ mpz_export(zb, &zlen, 1, 1, 0, 0, z);
+ if (zlen == 0) {
+ printf(" 00");
+ return;
+ }
+ if ((zlen & 3) != 0) {
+ k = 4 - (zlen & 3);
+ memmove(zb + k, zb, zlen);
+ memset(zb, 0, k);
+ zlen += k;
+ }
+ for (k = 0; k < zlen; k += 4) {
+ printf(" %02X%02X%02X%02X",
+ zb[k], zb[k + 1], zb[k + 2], zb[k + 3]);
+ }
+}
+
+/*
+ * Print out an i31 or i32 integer (for debug).
+ */
+static void
+print_u(uint32_t *x)
+{
+ size_t k;
+
+ if (x[0] == 0) {
+ printf(" 00000000 (0, 0)");
+ return;
+ }
+ for (k = (x[0] + 31) >> 5; k > 0; k --) {
+ printf(" %08lX", (unsigned long)x[k]);
+ }
+ printf(" (%u, %u)", (unsigned)(x[0] >> 5), (unsigned)(x[0] & 31));
+}
+
+/*
+ * Check that an i31/i32 number and a GMP number are equal.
+ */
+static void
+check_eqz(uint32_t *x, mpz_t z)
+{
+ unsigned char xb[1000];
+ unsigned char zb[1000];
+ size_t xlen, zlen;
+ int good;
+
+ xlen = ((x[0] + 31) & ~(uint32_t)31) >> 3;
+ impl->encode(xb, xlen, x);
+ mpz_export(zb, &zlen, 1, 1, 0, 0, z);
+ good = 1;
+ if (xlen < zlen) {
+ good = 0;
+ } else if (xlen > zlen) {
+ size_t u;
+
+ for (u = xlen; u > zlen; u --) {
+ if (xb[xlen - u] != 0) {
+ good = 0;
+ break;
+ }
+ }
+ }
+ good = good && memcmp(xb + xlen - zlen, zb, zlen) == 0;
+ if (!good) {
+ size_t u;
+
+ printf("Mismatch:\n");
+ printf(" x = ");
+ print_u(x);
+ printf("\n");
+ printf(" ex = ");
+ for (u = 0; u < xlen; u ++) {
+ printf("%02X", xb[u]);
+ }
+ printf("\n");
+ printf(" z = ");
+ print_z(z);
+ printf("\n");
+ exit(EXIT_FAILURE);
+ }
+}
+
+/* obsolete
+static void
+mp_to_br(uint32_t *mx, uint32_t x_bitlen, mpz_t x)
+{
+ uint32_t x_ebitlen;
+ size_t xlen;
+
+ if (mpz_sizeinbase(x, 2) > x_bitlen) {
+ abort();
+ }
+ x_ebitlen = ((x_bitlen / 31) << 5) + (x_bitlen % 31);
+ br_i31_zero(mx, x_ebitlen);
+ mpz_export(mx + 1, &xlen, -1, sizeof *mx, 0, 1, x);
+}
+*/
+
+static void
+test_modint(void)
+{
+ int i, j, k;
+ mpz_t p, a, b, v, t1;
+
+ printf("Test modular integers: ");
+ fflush(stdout);
+
+ gmp_randinit_mt(RNG);
+ mpz_init(p);
+ mpz_init(a);
+ mpz_init(b);
+ mpz_init(v);
+ mpz_init(t1);
+ mpz_set_ui(t1, (unsigned long)time(NULL));
+ gmp_randseed(RNG, t1);
+ for (k = 2; k <= 128; k ++) {
+ for (i = 0; i < 10; i ++) {
+ unsigned char ep[100], ea[100], eb[100], ev[100];
+ size_t plen, alen, blen, vlen;
+ uint32_t mp[40], ma[40], mb[40], mv[60], mx[100];
+ uint32_t mt1[40], mt2[40], mt3[40];
+ uint32_t ctl;
+ uint32_t mp0i;
+
+ rand_prime(p, k);
+ mpz_urandomm(a, RNG, p);
+ mpz_urandomm(b, RNG, p);
+ mpz_urandomb(v, RNG, k + 60);
+ if (mpz_sgn(b) == 0) {
+ mpz_set_ui(b, 1);
+ }
+ mpz_export(ep, &plen, 1, 1, 0, 0, p);
+ mpz_export(ea, &alen, 1, 1, 0, 0, a);
+ mpz_export(eb, &blen, 1, 1, 0, 0, b);
+ mpz_export(ev, &vlen, 1, 1, 0, 0, v);
+
+ impl->decode(mp, ep, plen);
+ if (impl->decode_mod(ma, ea, alen, mp) != 1) {
+ printf("Decode error\n");
+ printf(" ea = ");
+ print_z(a);
+ printf("\n");
+ printf(" p = ");
+ print_u(mp);
+ printf("\n");
+ exit(EXIT_FAILURE);
+ }
+ mp0i = impl->ninv(mp[1]);
+ if (impl->decode_mod(mb, eb, blen, mp) != 1) {
+ printf("Decode error\n");
+ printf(" eb = ");
+ print_z(b);
+ printf("\n");
+ printf(" p = ");
+ print_u(mp);
+ printf("\n");
+ exit(EXIT_FAILURE);
+ }
+ impl->decode(mv, ev, vlen);
+ check_eqz(mp, p);
+ check_eqz(ma, a);
+ check_eqz(mb, b);
+ check_eqz(mv, v);
+
+ impl->decode_mod(ma, ea, alen, mp);
+ impl->decode_mod(mb, eb, blen, mp);
+ ctl = impl->add(ma, mb, 1);
+ ctl |= impl->sub(ma, mp, 0) ^ (uint32_t)1;
+ impl->sub(ma, mp, ctl);
+ mpz_add(t1, a, b);
+ mpz_mod(t1, t1, p);
+ check_eqz(ma, t1);
+
+ impl->decode_mod(ma, ea, alen, mp);
+ impl->decode_mod(mb, eb, blen, mp);
+ impl->add(ma, mp, impl->sub(ma, mb, 1));
+ mpz_sub(t1, a, b);
+ mpz_mod(t1, t1, p);
+ check_eqz(ma, t1);
+
+ impl->decode_reduce(ma, ev, vlen, mp);
+ mpz_mod(t1, v, p);
+ check_eqz(ma, t1);
+
+ impl->decode(mv, ev, vlen);
+ impl->reduce(ma, mv, mp);
+ mpz_mod(t1, v, p);
+ check_eqz(ma, t1);
+
+ impl->decode_mod(ma, ea, alen, mp);
+ impl->to_monty(ma, mp);
+ mpz_mul_2exp(t1, a, ((k + impl->word_size - 1)
+ / impl->word_size) * impl->word_size);
+ mpz_mod(t1, t1, p);
+ check_eqz(ma, t1);
+ impl->from_monty(ma, mp, mp0i);
+ check_eqz(ma, a);
+
+ impl->decode_mod(ma, ea, alen, mp);
+ impl->decode_mod(mb, eb, blen, mp);
+ impl->to_monty(ma, mp);
+ impl->montymul(mt1, ma, mb, mp, mp0i);
+ mpz_mul(t1, a, b);
+ mpz_mod(t1, t1, p);
+ check_eqz(mt1, t1);
+
+ impl->decode_mod(ma, ea, alen, mp);
+ impl->modpow(ma, ev, vlen, mp, mp0i, mt1, mt2);
+ mpz_powm(t1, a, v, p);
+ check_eqz(ma, t1);
+
+ /*
+ br_modint_decode(ma, mp, ea, alen);
+ br_modint_decode(mb, mp, eb, blen);
+ if (!br_modint_div(ma, mb, mp, mt1, mt2, mt3)) {
+ fprintf(stderr, "division failed\n");
+ exit(EXIT_FAILURE);
+ }
+ mpz_sub_ui(t1, p, 2);
+ mpz_powm(t1, b, t1, p);
+ mpz_mul(t1, a, t1);
+ mpz_mod(t1, t1, p);
+ check_eqz(ma, t1);
+
+ br_modint_decode(ma, mp, ea, alen);
+ br_modint_decode(mb, mp, eb, blen);
+ for (j = 0; j <= (2 * k + 5); j ++) {
+ br_int_add(mx, j, ma, mb);
+ mpz_add(t1, a, b);
+ mpz_tdiv_r_2exp(t1, t1, j);
+ check_eqz(mx, t1);
+
+ br_int_mul(mx, j, ma, mb);
+ mpz_mul(t1, a, b);
+ mpz_tdiv_r_2exp(t1, t1, j);
+ check_eqz(mx, t1);
+ }
+ */
+ }
+ printf(".");
+ fflush(stdout);
+ }
+ mpz_clear(p);
+ mpz_clear(a);
+ mpz_clear(b);
+ mpz_clear(v);
+ mpz_clear(t1);
+
+ printf(" done.\n");
+ fflush(stdout);
+}
+
+#if 0
+static void
+test_RSA_core(void)
+{
+ int i, j, k;
+ mpz_t n, e, d, p, q, dp, dq, iq, t1, t2, phi;
+
+ printf("Test RSA core: ");
+ fflush(stdout);
+
+ gmp_randinit_mt(RNG);
+ mpz_init(n);
+ mpz_init(e);
+ mpz_init(d);
+ mpz_init(p);
+ mpz_init(q);
+ mpz_init(dp);
+ mpz_init(dq);
+ mpz_init(iq);
+ mpz_init(t1);
+ mpz_init(t2);
+ mpz_init(phi);
+ mpz_set_ui(t1, (unsigned long)time(NULL));
+ gmp_randseed(RNG, t1);
+
+ /*
+ * To test corner cases, we want to try RSA keys such that the
+ * lengths of both factors can be arbitrary modulo 2^32. Factors
+ * p and q need not be of the same length; p can be greater than
+ * q and q can be greater than p.
+ *
+ * To keep computation time reasonable, we use p and q factors of
+ * less than 128 bits; this is way too small for secure RSA,
+ * but enough to exercise all code paths (since we work only with
+ * 32-bit words).
+ */
+ for (i = 64; i <= 96; i ++) {
+ rand_prime(p, i);
+ for (j = i - 33; j <= i + 33; j ++) {
+ uint32_t mp[40], mq[40], mdp[40], mdq[40], miq[40];
+
+ /*
+ * Generate a RSA key pair, with p of length i bits,
+ * and q of length j bits.
+ */
+ do {
+ rand_prime(q, j);
+ } while (mpz_cmp(p, q) == 0);
+ mpz_mul(n, p, q);
+ mpz_set_ui(e, 65537);
+ mpz_sub_ui(t1, p, 1);
+ mpz_sub_ui(t2, q, 1);
+ mpz_mul(phi, t1, t2);
+ mpz_invert(d, e, phi);
+ mpz_mod(dp, d, t1);
+ mpz_mod(dq, d, t2);
+ mpz_invert(iq, q, p);
+
+ /*
+ * Convert the key pair elements to BearSSL arrays.
+ */
+ mp_to_br(mp, mpz_sizeinbase(p, 2), p);
+ mp_to_br(mq, mpz_sizeinbase(q, 2), q);
+ mp_to_br(mdp, mpz_sizeinbase(dp, 2), dp);
+ mp_to_br(mdq, mpz_sizeinbase(dq, 2), dq);
+ mp_to_br(miq, mp[0], iq);
+
+ /*
+ * Compute and check ten public/private operations.
+ */
+ for (k = 0; k < 10; k ++) {
+ uint32_t mx[40];
+
+ mpz_urandomm(t1, RNG, n);
+ mpz_powm(t2, t1, e, n);
+ mp_to_br(mx, mpz_sizeinbase(n, 2), t2);
+ br_rsa_private_core(mx, mp, mq, mdp, mdq, miq);
+ check_eqz(mx, t1);
+ }
+ }
+ printf(".");
+ fflush(stdout);
+ }
+
+ printf(" done.\n");
+ fflush(stdout);
+}
+#endif
+
+int
+main(void)
+{
+ printf("===== i32 ======\n");
+ impl = &i32_impl;
+ test_modint();
+ printf("===== i31 ======\n");
+ impl = &i31_impl;
+ test_modint();
+ /*
+ test_RSA_core();
+ */
+ return 0;
+}
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "inner.h"
+
+#define HASH_SIZE(cname) br_ ## cname ## _SIZE
+
+#define SPEED_HASH(Name, cname) \
+static void \
+test_speed_ ## cname(void) \
+{ \
+ unsigned char buf[8192]; \
+ unsigned char tmp[HASH_SIZE(cname)]; \
+ br_ ## cname ## _context mc; \
+ int i; \
+ long num; \
+ \
+ memset(buf, 'T', sizeof buf); \
+ for (i = 0; i < 10; i ++) { \
+ br_ ## cname ## _init(&mc); \
+ br_ ## cname ## _update(&mc, buf, sizeof buf); \
+ br_ ## cname ## _out(&mc, tmp); \
+ } \
+ num = 10; \
+ for (;;) { \
+ clock_t begin, end; \
+ double tt; \
+ long k; \
+ \
+ br_ ## cname ## _init(&mc); \
+ begin = clock(); \
+ for (k = num; k > 0; k --) { \
+ br_ ## cname ## _update(&mc, buf, sizeof buf); \
+ } \
+ end = clock(); \
+ br_ ## cname ## _out(&mc, tmp); \
+ tt = (double)(end - begin) / CLOCKS_PER_SEC; \
+ if (tt >= 2.0) { \
+ printf("%-30s %8.2f MB/s\n", #Name, \
+ ((double)sizeof buf) * (double)num \
+ / (tt * 1000000.0)); \
+ fflush(stdout); \
+ return; \
+ } \
+ num <<= 1; \
+ } \
+}
+
+#define BLOCK_SIZE(cname) br_ ## cname ## _BLOCK_SIZE
+
+#define SPEED_BLOCKCIPHER_CBC(Name, fname, cname, klen, dir) \
+static void \
+test_speed_ ## fname(void) \
+{ \
+ unsigned char key[klen]; \
+ unsigned char buf[8192 - (8192 % BLOCK_SIZE(cname))]; \
+ unsigned char iv[BLOCK_SIZE(cname)]; \
+ const br_block_cbc ## dir ## _class *vt; \
+ br_ ## cname ## _cbc ## dir ## _keys ec; \
+ int i; \
+ long num; \
+ \
+ memset(key, 'T', sizeof key); \
+ memset(buf, 'P', sizeof buf); \
+ memset(iv, 'X', sizeof iv); \
+ vt = &br_ ## cname ## _cbc ## dir ## _vtable; \
+ for (i = 0; i < 10; i ++) { \
+ vt->init(&ec.vtable, key, sizeof key); \
+ vt->run(&ec.vtable, iv, buf, sizeof buf); \
+ } \
+ num = 10; \
+ for (;;) { \
+ clock_t begin, end; \
+ double tt; \
+ long k; \
+ \
+ vt->init(&ec.vtable, key, sizeof key); \
+ begin = clock(); \
+ for (k = num; k > 0; k --) { \
+ vt->run(&ec.vtable, iv, buf, sizeof buf); \
+ } \
+ end = clock(); \
+ tt = (double)(end - begin) / CLOCKS_PER_SEC; \
+ if (tt >= 2.0) { \
+ printf("%-30s %8.2f MB/s\n", #Name, \
+ ((double)sizeof buf) * (double)num \
+ / (tt * 1000000.0)); \
+ fflush(stdout); \
+ return; \
+ } \
+ num <<= 1; \
+ } \
+}
+
+#define SPEED_BLOCKCIPHER_CTR(Name, fname, cname, klen) \
+static void \
+test_speed_ ## fname(void) \
+{ \
+ unsigned char key[klen]; \
+ unsigned char buf[8192 - (8192 % BLOCK_SIZE(cname))]; \
+ unsigned char iv[BLOCK_SIZE(cname) - 4]; \
+ const br_block_ctr_class *vt; \
+ br_ ## cname ## _ctr_keys ec; \
+ int i; \
+ long num; \
+ \
+ memset(key, 'T', sizeof key); \
+ memset(buf, 'P', sizeof buf); \
+ memset(iv, 'X', sizeof iv); \
+ vt = &br_ ## cname ## _ctr_vtable; \
+ for (i = 0; i < 10; i ++) { \
+ vt->init(&ec.vtable, key, sizeof key); \
+ vt->run(&ec.vtable, iv, 1, buf, sizeof buf); \
+ } \
+ num = 10; \
+ for (;;) { \
+ clock_t begin, end; \
+ double tt; \
+ long k; \
+ \
+ vt->init(&ec.vtable, key, sizeof key); \
+ begin = clock(); \
+ for (k = num; k > 0; k --) { \
+ vt->run(&ec.vtable, iv, 1, buf, sizeof buf); \
+ } \
+ end = clock(); \
+ tt = (double)(end - begin) / CLOCKS_PER_SEC; \
+ if (tt >= 2.0) { \
+ printf("%-30s %8.2f MB/s\n", #Name, \
+ ((double)sizeof buf) * (double)num \
+ / (tt * 1000000.0)); \
+ fflush(stdout); \
+ return; \
+ } \
+ num <<= 1; \
+ } \
+}
+
+SPEED_HASH(MD5, md5)
+SPEED_HASH(SHA-1, sha1)
+SPEED_HASH(SHA-256, sha256)
+SPEED_HASH(SHA-512, sha512)
+
+#define SPEED_AES(iname) \
+SPEED_BLOCKCIPHER_CBC(AES-128 CBC encrypt (iname), aes128_ ## iname ## _cbcenc, aes_ ## iname, 16, enc) \
+SPEED_BLOCKCIPHER_CBC(AES-128 CBC decrypt (iname), aes128_ ## iname ## _cbcdec, aes_ ## iname, 16, dec) \
+SPEED_BLOCKCIPHER_CBC(AES-192 CBC encrypt (iname), aes192_ ## iname ## _cbcenc, aes_ ## iname, 24, enc) \
+SPEED_BLOCKCIPHER_CBC(AES-192 CBC decrypt (iname), aes192_ ## iname ## _cbcdec, aes_ ## iname, 24, dec) \
+SPEED_BLOCKCIPHER_CBC(AES-256 CBC encrypt (iname), aes256_ ## iname ## _cbcenc, aes_ ## iname, 32, enc) \
+SPEED_BLOCKCIPHER_CBC(AES-256 CBC decrypt (iname), aes256_ ## iname ## _cbcdec, aes_ ## iname, 32, dec) \
+SPEED_BLOCKCIPHER_CTR(AES-128 CTR (iname), aes128_ ## iname ## _ctr, aes_ ## iname, 16) \
+SPEED_BLOCKCIPHER_CTR(AES-192 CTR (iname), aes192_ ## iname ## _ctr, aes_ ## iname, 24) \
+SPEED_BLOCKCIPHER_CTR(AES-256 CTR (iname), aes256_ ## iname ## _ctr, aes_ ## iname, 32)
+
+SPEED_AES(big)
+SPEED_AES(small)
+SPEED_AES(ct)
+SPEED_AES(ct64)
+
+#define SPEED_DES(iname) \
+SPEED_BLOCKCIPHER_CBC(DES CBC encrypt (iname), des_ ## iname ## _cbcenc, des_ ## iname, 8, enc) \
+SPEED_BLOCKCIPHER_CBC(DES CBC decrypt (iname), des_ ## iname ## _cbcdec, des_ ## iname, 8, dec) \
+SPEED_BLOCKCIPHER_CBC(3DES CBC encrypt (iname), 3des_ ## iname ## _cbcenc, des_ ## iname, 24, enc) \
+SPEED_BLOCKCIPHER_CBC(3DES CBC decrypt (iname), 3des_ ## iname ## _cbcdec, des_ ## iname, 24, dec)
+
+SPEED_DES(tab)
+SPEED_DES(ct)
+
+static void
+test_speed_ghash_inner(char *name, br_ghash gh)
+{
+ unsigned char buf[8192], h[16], y[16];
+ int i;
+ long num;
+
+ memset(buf, 'T', sizeof buf);
+ memset(h, 'P', sizeof h);
+ memset(y, 0, sizeof y);
+ for (i = 0; i < 10; i ++) {
+ gh(y, h, buf, sizeof buf);
+ }
+ num = 10;
+ for (;;) {
+ clock_t begin, end;
+ double tt;
+ long k;
+
+ begin = clock();
+ for (k = num; k > 0; k --) {
+ gh(y, h, buf, sizeof buf);
+ }
+ end = clock();
+ tt = (double)(end - begin) / CLOCKS_PER_SEC;
+ if (tt >= 2.0) {
+ printf("%-30s %8.2f MB/s\n", name,
+ ((double)sizeof buf) * (double)num
+ / (tt * 1000000.0));
+ fflush(stdout);
+ return;
+ }
+ num <<= 1;
+ }
+}
+
+static void
+test_speed_ghash_ctmul(void)
+{
+ test_speed_ghash_inner("GHASH (ctmul)", &br_ghash_ctmul);
+}
+
+static void
+test_speed_ghash_ctmul32(void)
+{
+ test_speed_ghash_inner("GHASH (ctmul32)", &br_ghash_ctmul32);
+}
+
+static void
+test_speed_ghash_ctmul64(void)
+{
+ test_speed_ghash_inner("GHASH (ctmul64)", &br_ghash_ctmul64);
+}
+
+static const unsigned char RSA_N[] = {
+ 0xE9, 0xF2, 0x4A, 0x2F, 0x96, 0xDF, 0x0A, 0x23,
+ 0x01, 0x85, 0xF1, 0x2C, 0xB2, 0xA8, 0xEF, 0x23,
+ 0xCE, 0x2E, 0xB0, 0x4E, 0x18, 0x31, 0x95, 0x5B,
+ 0x98, 0x2D, 0x9B, 0x8C, 0xE3, 0x1A, 0x2B, 0x96,
+ 0xB5, 0xC7, 0xEE, 0xED, 0x72, 0x43, 0x2D, 0xFE,
+ 0x7F, 0x61, 0x33, 0xEA, 0x14, 0xFC, 0xDE, 0x80,
+ 0x17, 0x42, 0xF0, 0xF3, 0xC3, 0xC7, 0x89, 0x47,
+ 0x76, 0x5B, 0xFA, 0x33, 0xC4, 0x8C, 0x94, 0xDE,
+ 0x6A, 0x75, 0xD8, 0x1A, 0xF4, 0x49, 0xBC, 0xF3,
+ 0xB7, 0x9E, 0x2C, 0x8D, 0xEC, 0x5A, 0xEE, 0xBF,
+ 0x4B, 0x5A, 0x7F, 0xEF, 0x21, 0x39, 0xDB, 0x1D,
+ 0x83, 0x5E, 0x7E, 0x2F, 0xAA, 0x5E, 0xBA, 0x28,
+ 0xC3, 0xA2, 0x53, 0x19, 0xFB, 0x2F, 0x78, 0x6B,
+ 0x14, 0x60, 0x49, 0x3C, 0xCC, 0x1B, 0xE9, 0x1E,
+ 0x3D, 0x10, 0xA4, 0xEB, 0x7F, 0x66, 0x98, 0xF6,
+ 0xC3, 0xAC, 0x35, 0xF5, 0x01, 0x84, 0xFF, 0x7D,
+ 0x1F, 0x72, 0xBE, 0xB4, 0xD1, 0x89, 0xC8, 0xDD,
+ 0x44, 0xE7, 0xB5, 0x2E, 0x2C, 0xE1, 0x85, 0xF5,
+ 0x15, 0x50, 0xA9, 0x08, 0xC7, 0x67, 0xD9, 0x2B,
+ 0x6C, 0x11, 0xB3, 0xEB, 0x28, 0x8D, 0xF4, 0xCC,
+ 0xE3, 0xC3, 0xC5, 0x04, 0x0E, 0x7C, 0x8D, 0xDB,
+ 0x39, 0x06, 0x6A, 0x74, 0x75, 0xDF, 0xA8, 0x0F,
+ 0xDA, 0x67, 0x5A, 0x73, 0x1E, 0xFD, 0x8E, 0x4C,
+ 0xEE, 0x17, 0xEE, 0x1E, 0x67, 0xDB, 0x98, 0x70,
+ 0x60, 0xF7, 0xB9, 0xB5, 0x1F, 0x19, 0x93, 0xD6,
+ 0x3F, 0x2F, 0x1F, 0xB6, 0x5B, 0x59, 0xAA, 0x85,
+ 0xBB, 0x25, 0xE4, 0x13, 0xEF, 0xE7, 0xB9, 0x87,
+ 0x9C, 0x3F, 0x5E, 0xE4, 0x08, 0xA3, 0x51, 0xCF,
+ 0x8B, 0xAD, 0xF4, 0xE6, 0x1A, 0x5F, 0x51, 0xDD,
+ 0xA8, 0xBE, 0xE8, 0xD1, 0x20, 0x19, 0x61, 0x6C,
+ 0x18, 0xAB, 0xCA, 0x0A, 0xD9, 0x82, 0xA6, 0x94,
+ 0xD5, 0x69, 0x2A, 0xF6, 0x43, 0x66, 0x31, 0x09
+};
+
+static const unsigned char RSA_E[] = {
+ 0x01, 0x00, 0x01
+};
+
+static const unsigned char RSA_P[] = {
+ 0xFD, 0x39, 0x40, 0x56, 0x20, 0x80, 0xC5, 0x81,
+ 0x4C, 0x5F, 0x0C, 0x1A, 0x52, 0x84, 0x03, 0x2F,
+ 0xCE, 0x82, 0xB0, 0xD8, 0x30, 0x23, 0x7F, 0x77,
+ 0x45, 0xC2, 0x01, 0xC4, 0x68, 0x96, 0x0D, 0xA7,
+ 0x22, 0xA9, 0x6C, 0xA9, 0x1A, 0x33, 0xE5, 0x2F,
+ 0xB5, 0x07, 0x9A, 0xF9, 0xEA, 0x33, 0xA5, 0xC8,
+ 0x96, 0x60, 0x6A, 0xCA, 0xEB, 0xE5, 0x6E, 0x09,
+ 0x46, 0x7E, 0x2D, 0xEF, 0x93, 0x7D, 0x56, 0xED,
+ 0x75, 0x70, 0x3B, 0x96, 0xC4, 0xD5, 0xDB, 0x0B,
+ 0x3F, 0x69, 0xDF, 0x06, 0x18, 0x76, 0xF4, 0xCF,
+ 0xF8, 0x84, 0x22, 0xDF, 0xBD, 0x71, 0x62, 0x7B,
+ 0x67, 0x99, 0xBC, 0x09, 0x95, 0x54, 0xA4, 0x98,
+ 0x83, 0xF5, 0xA9, 0xCF, 0x09, 0xA5, 0x1F, 0x61,
+ 0x25, 0xB4, 0x70, 0x6C, 0x91, 0xB8, 0xB3, 0xD0,
+ 0xCE, 0x9C, 0x45, 0x65, 0x9B, 0xEF, 0xD4, 0x70,
+ 0xBE, 0x86, 0xD2, 0x98, 0x5D, 0xEB, 0xE3, 0xFF
+};
+
+static const unsigned char RSA_Q[] = {
+ 0xEC, 0x82, 0xEE, 0x63, 0x5F, 0x40, 0x52, 0xDB,
+ 0x38, 0x7A, 0x37, 0x6A, 0x54, 0x5B, 0xD9, 0xA0,
+ 0x73, 0xB4, 0xBB, 0x52, 0xB2, 0x84, 0x07, 0xD0,
+ 0xCC, 0x82, 0x0D, 0x20, 0xB3, 0xFA, 0xD5, 0xB6,
+ 0x25, 0x92, 0x35, 0x4D, 0xB4, 0xC7, 0x36, 0x48,
+ 0xCE, 0x5E, 0x21, 0x4A, 0xA6, 0x74, 0x65, 0xF4,
+ 0x7D, 0x1D, 0xBC, 0x3B, 0xE2, 0xF4, 0x3E, 0x11,
+ 0x58, 0x10, 0x6C, 0x04, 0x46, 0x9E, 0x8D, 0x57,
+ 0xE0, 0x04, 0xE2, 0xEC, 0x47, 0xCF, 0xB3, 0x2A,
+ 0xFD, 0x4C, 0x55, 0x18, 0xDB, 0xDE, 0x3B, 0xDC,
+ 0xF4, 0x5B, 0xDA, 0xF3, 0x1A, 0xC8, 0x41, 0x6F,
+ 0x73, 0x3B, 0xFE, 0x3C, 0xA0, 0xDB, 0xBA, 0x6E,
+ 0x65, 0xA5, 0xE8, 0x02, 0xA5, 0x6C, 0xEA, 0x03,
+ 0xF6, 0x99, 0xF7, 0xCB, 0x4B, 0xB7, 0x11, 0x51,
+ 0x93, 0x88, 0x3F, 0xF9, 0x06, 0x85, 0xA9, 0x1E,
+ 0xCA, 0x64, 0xF8, 0x11, 0xA5, 0x1A, 0xCA, 0xF7
+};
+
+static const unsigned char RSA_DP[] = {
+ 0x77, 0x95, 0xE0, 0x02, 0x4C, 0x9B, 0x43, 0xAA,
+ 0xCA, 0x4C, 0x60, 0xC4, 0xD5, 0x8F, 0x2E, 0x8A,
+ 0x17, 0x36, 0xB5, 0x19, 0x83, 0xB2, 0x5F, 0xF2,
+ 0x0D, 0xE9, 0x8F, 0x38, 0x18, 0x44, 0x34, 0xF2,
+ 0x67, 0x76, 0x27, 0xB0, 0xBC, 0x85, 0x21, 0x89,
+ 0x24, 0x2F, 0x11, 0x4B, 0x51, 0x05, 0x4F, 0x17,
+ 0xA9, 0x9C, 0xA3, 0x12, 0x6D, 0xD1, 0x0D, 0xE4,
+ 0x27, 0x7C, 0x53, 0x69, 0x3E, 0xF8, 0x04, 0x63,
+ 0x64, 0x00, 0xBA, 0xC3, 0x7A, 0xF5, 0x9B, 0xDA,
+ 0x75, 0xFA, 0x23, 0xAF, 0x17, 0x42, 0xA6, 0x5E,
+ 0xC8, 0xF8, 0x6E, 0x17, 0xC7, 0xB9, 0x92, 0x4E,
+ 0xC1, 0x20, 0x63, 0x23, 0x0B, 0x78, 0xCB, 0xBA,
+ 0x93, 0x27, 0x23, 0x28, 0x79, 0x5F, 0x97, 0xB0,
+ 0x23, 0x44, 0x51, 0x8B, 0x94, 0x4D, 0xEB, 0xED,
+ 0x82, 0x85, 0x5E, 0x68, 0x9B, 0xF9, 0xE9, 0x13,
+ 0xCD, 0x86, 0x92, 0x52, 0x0E, 0x98, 0xE6, 0x35
+};
+
+static const unsigned char RSA_DQ[] = {
+ 0xD8, 0xDD, 0x71, 0xB3, 0x62, 0xBA, 0xBB, 0x7E,
+ 0xD1, 0xF9, 0x96, 0xE8, 0x83, 0xB3, 0xB9, 0x08,
+ 0x9C, 0x30, 0x03, 0x77, 0xDF, 0xC2, 0x9A, 0xDC,
+ 0x05, 0x39, 0xD6, 0xC9, 0xBE, 0xDE, 0x68, 0xA9,
+ 0xDD, 0x27, 0x84, 0x82, 0xDD, 0x19, 0xB1, 0x97,
+ 0xEE, 0xCA, 0x77, 0x22, 0x59, 0x20, 0xEF, 0xFF,
+ 0xCF, 0xDD, 0xBD, 0x24, 0xF8, 0x84, 0xD6, 0x88,
+ 0xD6, 0xC4, 0x30, 0x17, 0x77, 0x9D, 0x98, 0xA3,
+ 0x14, 0x01, 0xC7, 0x05, 0xBB, 0x0F, 0x23, 0x0D,
+ 0x6F, 0x37, 0x57, 0xEC, 0x34, 0x67, 0x41, 0x62,
+ 0xE8, 0x19, 0x75, 0xD9, 0x66, 0x1C, 0x6B, 0x8B,
+ 0xC3, 0x11, 0x26, 0x9C, 0xF7, 0x2E, 0xA3, 0x72,
+ 0xE8, 0xF7, 0xC8, 0x96, 0xEC, 0x92, 0xC2, 0xBD,
+ 0xA1, 0x98, 0x2A, 0x93, 0x99, 0xB8, 0xA2, 0x43,
+ 0xB7, 0xD0, 0xBE, 0x40, 0x1C, 0x8F, 0xE0, 0xB4,
+ 0x20, 0x07, 0x97, 0x43, 0xAE, 0xAD, 0xB3, 0x9F
+};
+
+static const unsigned char RSA_IQ[] = {
+ 0xB7, 0xE2, 0x60, 0xA9, 0x62, 0xEC, 0xEC, 0x0B,
+ 0x57, 0x02, 0x96, 0xF9, 0x36, 0x35, 0x2C, 0x37,
+ 0xAF, 0xC2, 0xEE, 0x71, 0x49, 0x26, 0x8E, 0x0F,
+ 0x27, 0xB1, 0xFA, 0x0F, 0xEA, 0xDC, 0xF0, 0x8B,
+ 0x53, 0x6C, 0xB2, 0x46, 0x27, 0xCD, 0x29, 0xA2,
+ 0x35, 0x0F, 0x5D, 0x8A, 0x3F, 0x20, 0x8C, 0x13,
+ 0x3D, 0xA1, 0xFF, 0x85, 0x91, 0x99, 0xE8, 0x50,
+ 0xED, 0xF1, 0x29, 0x00, 0xEE, 0x24, 0x90, 0xB5,
+ 0x5F, 0x3A, 0x74, 0x26, 0xD7, 0xA2, 0x24, 0x8D,
+ 0x89, 0x88, 0xD8, 0x35, 0x22, 0x22, 0x8A, 0x66,
+ 0x5D, 0x5C, 0xDE, 0x83, 0x8C, 0xFA, 0x27, 0xE6,
+ 0xB9, 0xEB, 0x72, 0x08, 0xCD, 0x53, 0x4B, 0x93,
+ 0x0F, 0xAD, 0xC3, 0xF8, 0x7C, 0xFE, 0x84, 0xD7,
+ 0x08, 0xF3, 0xBE, 0x3D, 0x60, 0x1E, 0x95, 0x8D,
+ 0x44, 0x5B, 0x65, 0x7E, 0xC1, 0x30, 0xC3, 0x84,
+ 0xC0, 0xB0, 0xFE, 0xBF, 0x28, 0x54, 0x1E, 0xC4
+};
+
+static const br_rsa_public_key RSA_PK = {
+ (void *)RSA_N, sizeof RSA_N,
+ (void *)RSA_E, sizeof RSA_E
+};
+
+static const br_rsa_private_key RSA_SK = {
+ 2048,
+ (void *)RSA_P, sizeof RSA_P,
+ (void *)RSA_Q, sizeof RSA_Q,
+ (void *)RSA_DP, sizeof RSA_DP,
+ (void *)RSA_DQ, sizeof RSA_DQ,
+ (void *)RSA_IQ, sizeof RSA_IQ
+};
+
+static void
+test_speed_rsa_inner(char *name,
+ br_rsa_public fpub, br_rsa_private fpriv)
+{
+ unsigned char tmp[sizeof RSA_N];
+ int i;
+ long num;
+
+ memset(tmp, 'R', sizeof tmp);
+ tmp[0] = 0;
+ for (i = 0; i < 10; i ++) {
+ if (!fpriv(tmp, &RSA_SK)) {
+ abort();
+ }
+ }
+ num = 10;
+ for (;;) {
+ clock_t begin, end;
+ double tt;
+ long k;
+
+ begin = clock();
+ for (k = num; k > 0; k --) {
+ fpriv(tmp, &RSA_SK);
+ }
+ end = clock();
+ tt = (double)(end - begin) / CLOCKS_PER_SEC;
+ if (tt >= 2.0) {
+ printf("%-30s %8.2f priv/s\n", name,
+ (double)num / tt);
+ fflush(stdout);
+ break;
+ }
+ num <<= 1;
+ }
+ for (i = 0; i < 10; i ++) {
+ if (!fpub(tmp, sizeof tmp, &RSA_PK)) {
+ abort();
+ }
+ }
+ num = 10;
+ for (;;) {
+ clock_t begin, end;
+ double tt;
+ long k;
+
+ begin = clock();
+ for (k = num; k > 0; k --) {
+ fpub(tmp, sizeof tmp, &RSA_PK);
+ }
+ end = clock();
+ tt = (double)(end - begin) / CLOCKS_PER_SEC;
+ if (tt >= 2.0) {
+ printf("%-30s %8.2f pub/s\n", name,
+ (double)num / tt);
+ fflush(stdout);
+ break;
+ }
+ num <<= 1;
+ }
+}
+
+static void
+test_speed_rsa_i31(void)
+{
+ test_speed_rsa_inner("RSA i31",
+ &br_rsa_i31_public, &br_rsa_i31_private);
+}
+
+static void
+test_speed_rsa_i32(void)
+{
+ test_speed_rsa_inner("RSA i32",
+ &br_rsa_i32_public, &br_rsa_i32_private);
+}
+
+static void
+test_speed_ec_inner(const char *name,
+ const br_ec_impl *impl, const br_ec_curve_def *cd)
+{
+ unsigned char bx[80], U[160];
+ uint32_t x[22], n[22];
+ size_t nlen, ulen;
+ int i;
+ long num;
+
+ nlen = cd->order_len;
+ br_i31_decode(n, cd->order, nlen);
+ memset(bx, 'T', sizeof bx);
+ br_i31_decode_reduce(x, bx, sizeof bx, n);
+ br_i31_encode(bx, nlen, x);
+ ulen = cd->generator_len;
+ memcpy(U, cd->generator, ulen);
+ for (i = 0; i < 10; i ++) {
+ impl->mul(U, ulen, bx, nlen, cd->curve);
+ }
+ num = 10;
+ for (;;) {
+ clock_t begin, end;
+ double tt;
+ long k;
+
+ begin = clock();
+ for (k = num; k > 0; k --) {
+ impl->mul(U, ulen, bx, nlen, cd->curve);
+ }
+ end = clock();
+ tt = (double)(end - begin) / CLOCKS_PER_SEC;
+ if (tt >= 2.0) {
+ printf("%-30s %8.2f mul/s\n", name,
+ (double)num / tt);
+ fflush(stdout);
+ break;
+ }
+ num <<= 1;
+ }
+}
+
+static void
+test_speed_ec_prime_i31(void)
+{
+ test_speed_ec_inner("EC i31 P-256", &br_ec_prime_i31, &br_secp256r1);
+ test_speed_ec_inner("EC i31 P-384", &br_ec_prime_i31, &br_secp384r1);
+ test_speed_ec_inner("EC i31 P-521", &br_ec_prime_i31, &br_secp521r1);
+}
+
+static void
+test_speed_ecdsa_inner(const char *name,
+ const br_ec_impl *impl, const br_ec_curve_def *cd,
+ br_ecdsa_sign sign, br_ecdsa_vrfy vrfy)
+{
+ unsigned char bx[80], U[160], hv[32], sig[160];
+ uint32_t x[22], n[22];
+ size_t nlen, ulen, sig_len;
+ int i;
+ long num;
+ br_ec_private_key sk;
+ br_ec_public_key pk;
+
+ nlen = cd->order_len;
+ br_i31_decode(n, cd->order, nlen);
+ memset(bx, 'T', sizeof bx);
+ br_i31_decode_reduce(x, bx, sizeof bx, n);
+ br_i31_encode(bx, nlen, x);
+ ulen = cd->generator_len;
+ memcpy(U, cd->generator, ulen);
+ impl->mul(U, ulen, bx, nlen, cd->curve);
+ sk.curve = cd->curve;
+ sk.x = bx;
+ sk.xlen = nlen;
+ pk.curve = cd->curve;
+ pk.q = U;
+ pk.qlen = ulen;
+
+ memset(hv, 'H', sizeof hv);
+ sig_len = sign(impl, &br_sha256_vtable, hv, &sk, sig);
+ if (vrfy(impl, hv, sizeof hv, &pk, sig, sig_len) != 1) {
+ fprintf(stderr, "self-test sign/verify failed\n");
+ exit(EXIT_FAILURE);
+ }
+
+ for (i = 0; i < 10; i ++) {
+ hv[1] ++;
+ sign(impl, &br_sha256_vtable, hv, &sk, sig);
+ vrfy(impl, hv, sizeof hv, &pk, sig, sig_len);
+ }
+
+ num = 10;
+ for (;;) {
+ clock_t begin, end;
+ double tt;
+ long k;
+
+ begin = clock();
+ for (k = num; k > 0; k --) {
+ hv[1] ++;
+ sig_len = sign(impl, &br_sha256_vtable, hv, &sk, sig);
+ }
+ end = clock();
+ tt = (double)(end - begin) / CLOCKS_PER_SEC;
+ if (tt >= 2.0) {
+ printf("%-30s %8.2f sign/s\n", name,
+ (double)num / tt);
+ fflush(stdout);
+ break;
+ }
+ num <<= 1;
+ }
+
+ num = 10;
+ for (;;) {
+ clock_t begin, end;
+ double tt;
+ long k;
+
+ begin = clock();
+ for (k = num; k > 0; k --) {
+ vrfy(impl, hv, sizeof hv, &pk, sig, sig_len);
+ }
+ end = clock();
+ tt = (double)(end - begin) / CLOCKS_PER_SEC;
+ if (tt >= 2.0) {
+ printf("%-30s %8.2f verify/s\n", name,
+ (double)num / tt);
+ fflush(stdout);
+ break;
+ }
+ num <<= 1;
+ }
+}
+
+static void
+test_speed_ecdsa_i31(void)
+{
+ test_speed_ecdsa_inner("ECDSA i31 P-256",
+ &br_ec_prime_i31, &br_secp256r1,
+ &br_ecdsa_i31_sign_asn1,
+ &br_ecdsa_i31_vrfy_asn1);
+ test_speed_ecdsa_inner("ECDSA i31 P-384",
+ &br_ec_prime_i31, &br_secp384r1,
+ &br_ecdsa_i31_sign_asn1,
+ &br_ecdsa_i31_vrfy_asn1);
+ test_speed_ecdsa_inner("ECDSA i31 P-521",
+ &br_ec_prime_i31, &br_secp521r1,
+ &br_ecdsa_i31_sign_asn1,
+ &br_ecdsa_i31_vrfy_asn1);
+}
+
+#if 0
+/* obsolete */
+static void
+test_speed_ec_prime_i31_inner(const char *name,
+ const unsigned char *bg, const br_ec_prime_i31_curve *cc)
+{
+ unsigned char bx[80], point[160];
+ uint32_t x[BR_EC_I31_LEN];
+ br_ec_prime_i31_jacobian P;
+ uint32_t xbl;
+ size_t plen;
+ int i;
+ long num;
+
+ xbl = cc->p[0];
+ xbl -= (xbl >> 5);
+ plen = (xbl + 7) >> 3;
+ memset(bx, 'T', sizeof bx);
+ br_i31_decode_reduce(x, bx, sizeof bx, cc->p);
+ br_i31_encode(bx, plen, x);
+ br_ec_prime_i31_decode(&P, bg, 1 + (plen << 1), cc);
+ for (i = 0; i < 10; i ++) {
+ br_ec_prime_i31_mul(&P, bx, plen, cc);
+ br_ec_prime_i31_encode(point, &P, cc);
+ }
+ num = 10;
+ for (;;) {
+ clock_t begin, end;
+ double tt;
+ long k;
+
+ begin = clock();
+ for (k = num; k > 0; k --) {
+ br_ec_prime_i31_mul(&P, bx, plen, cc);
+ br_ec_prime_i31_encode(point, &P, cc);
+ }
+ end = clock();
+ tt = (double)(end - begin) / CLOCKS_PER_SEC;
+ if (tt >= 2.0) {
+ printf("%-30s %8.2f mul/s\n", name,
+ (double)num / tt);
+ fflush(stdout);
+ break;
+ }
+ num <<= 1;
+ }
+}
+
+static void
+test_speed_ec_prime_i31(void)
+{
+ test_speed_ec_prime_i31_inner("EC i31 P-256",
+ br_g_secp256r1, &br_ec_prime_i31_secp256r1);
+ test_speed_ec_prime_i31_inner("EC i31 P-384",
+ br_g_secp384r1, &br_ec_prime_i31_secp384r1);
+ test_speed_ec_prime_i31_inner("EC i31 P-521",
+ br_g_secp521r1, &br_ec_prime_i31_secp521r1);
+}
+
+static void
+test_speed_ec_prime_i32_inner(const char *name,
+ const unsigned char *bg, const br_ec_prime_i32_curve *cc)
+{
+ unsigned char bx[80], point[160];
+ uint32_t x[BR_EC_I32_LEN];
+ br_ec_prime_i32_jacobian P;
+ size_t plen;
+ int i;
+ long num;
+
+ plen = (cc->p[0] + 7) >> 3;
+ memset(bx, 'T', sizeof bx);
+ br_i32_decode_reduce(x, bx, sizeof bx, cc->p);
+ br_i32_encode(bx, plen, x);
+ br_ec_prime_i32_decode(&P, bg, 1 + (plen << 1), cc);
+ for (i = 0; i < 10; i ++) {
+ br_ec_prime_i32_mul(&P, bx, plen, cc);
+ br_ec_prime_i32_encode(point, &P, cc);
+ }
+ num = 10;
+ for (;;) {
+ clock_t begin, end;
+ double tt;
+ long k;
+
+ begin = clock();
+ for (k = num; k > 0; k --) {
+ br_ec_prime_i32_mul(&P, bx, plen, cc);
+ br_ec_prime_i32_encode(point, &P, cc);
+ }
+ end = clock();
+ tt = (double)(end - begin) / CLOCKS_PER_SEC;
+ if (tt >= 2.0) {
+ printf("%-30s %8.2f mul/s\n", name,
+ (double)num / tt);
+ fflush(stdout);
+ break;
+ }
+ num <<= 1;
+ }
+}
+
+static void
+test_speed_ec_prime_i32(void)
+{
+ test_speed_ec_prime_i32_inner("EC i32 P-256",
+ br_g_secp256r1, &br_ec_prime_i32_secp256r1);
+ test_speed_ec_prime_i32_inner("EC i32 P-384",
+ br_g_secp384r1, &br_ec_prime_i32_secp384r1);
+ test_speed_ec_prime_i32_inner("EC i32 P-521",
+ br_g_secp521r1, &br_ec_prime_i32_secp521r1);
+}
+#endif
+
+static void
+test_speed_i31(void)
+{
+ static const unsigned char bp[] = {
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xBC, 0xE6, 0xFA, 0xAD, 0xA7, 0x17, 0x9E, 0x84,
+ 0xF3, 0xB9, 0xCA, 0xC2, 0xFC, 0x63, 0x25, 0x51
+ };
+
+ unsigned char tmp[60 + sizeof bp];
+ uint32_t p[10], x[10], y[10], z[10], p0i;
+ int i;
+ long num;
+
+ br_i31_decode(p, bp, sizeof bp);
+ p0i = br_i31_ninv31(p[1]);
+ memset(tmp, 'T', sizeof tmp);
+ br_i31_decode_reduce(x, tmp, sizeof tmp, p);
+ memset(tmp, 'U', sizeof tmp);
+ br_i31_decode_reduce(y, tmp, sizeof tmp, p);
+
+ for (i = 0; i < 10; i ++) {
+ br_i31_to_monty(x, p);
+ }
+ num = 10;
+ for (;;) {
+ clock_t begin, end;
+ double tt;
+ long k;
+
+ begin = clock();
+ for (k = num; k > 0; k --) {
+ br_i31_to_monty(x, p);
+ }
+ end = clock();
+ tt = (double)(end - begin) / CLOCKS_PER_SEC;
+ if (tt >= 2.0) {
+ printf("%-30s %8.2f ops/s\n", "i31 to_monty",
+ (double)num / tt);
+ fflush(stdout);
+ break;
+ }
+ num <<= 1;
+ }
+
+ for (i = 0; i < 10; i ++) {
+ br_i31_from_monty(x, p, p0i);
+ }
+ num = 10;
+ for (;;) {
+ clock_t begin, end;
+ double tt;
+ long k;
+
+ begin = clock();
+ for (k = num; k > 0; k --) {
+ br_i31_from_monty(x, p, p0i);
+ }
+ end = clock();
+ tt = (double)(end - begin) / CLOCKS_PER_SEC;
+ if (tt >= 2.0) {
+ printf("%-30s %8.2f ops/s\n", "i31 from_monty",
+ (double)num / tt);
+ fflush(stdout);
+ break;
+ }
+ num <<= 1;
+ }
+
+ for (i = 0; i < 10; i ++) {
+ br_i31_montymul(z, x, y, p, p0i);
+ }
+ num = 10;
+ for (;;) {
+ clock_t begin, end;
+ double tt;
+ long k;
+
+ begin = clock();
+ for (k = num; k > 0; k --) {
+ br_i31_montymul(z, x, y, p, p0i);
+ }
+ end = clock();
+ tt = (double)(end - begin) / CLOCKS_PER_SEC;
+ if (tt >= 2.0) {
+ printf("%-30s %8.2f ops/s\n", "i31 montymul",
+ (double)num / tt);
+ fflush(stdout);
+ break;
+ }
+ num <<= 1;
+ }
+}
+
+#if 0
+
+static unsigned char P2048[] = {
+ 0xFD, 0xB6, 0xE0, 0x3E, 0x00, 0x49, 0x4C, 0xF0, 0x69, 0x3A, 0xDD, 0x7D,
+ 0xF8, 0xA2, 0x41, 0xB0, 0x6C, 0x67, 0xC5, 0xBA, 0xB8, 0x46, 0x80, 0xF5,
+ 0xBF, 0xAB, 0x98, 0xFC, 0x84, 0x73, 0xA5, 0x63, 0xC9, 0x52, 0x12, 0xDA,
+ 0x4C, 0xC1, 0x5B, 0x9D, 0x8D, 0xDF, 0xCD, 0xFE, 0xC5, 0xAD, 0x5A, 0x6F,
+ 0xDD, 0x02, 0xD9, 0xEC, 0x71, 0xEF, 0xEB, 0xB6, 0x95, 0xED, 0x94, 0x25,
+ 0x0E, 0x63, 0xDD, 0x6A, 0x52, 0xC7, 0x93, 0xAF, 0x85, 0x9D, 0x2C, 0xBE,
+ 0x5C, 0xBE, 0x35, 0xD8, 0xDD, 0x39, 0xEF, 0x1B, 0xB1, 0x49, 0x67, 0xB2,
+ 0x33, 0xC9, 0x7C, 0xE1, 0x51, 0x79, 0x51, 0x59, 0xCA, 0x6E, 0x2A, 0xDF,
+ 0x0D, 0x76, 0x1C, 0xE7, 0xA5, 0xC0, 0x1E, 0x6C, 0x56, 0x3A, 0x32, 0xE5,
+ 0xB5, 0xC5, 0xD4, 0xDB, 0xFE, 0xFF, 0xF8, 0xF2, 0x96, 0xA9, 0xC9, 0x65,
+ 0x59, 0x9E, 0x01, 0x79, 0x9D, 0x38, 0x68, 0x0F, 0xAD, 0x43, 0x3A, 0xD6,
+ 0x84, 0x0A, 0xE2, 0xEF, 0x96, 0xC1, 0x6D, 0x89, 0x74, 0x19, 0x63, 0x82,
+ 0x3B, 0xA0, 0x9C, 0xBA, 0x78, 0xDE, 0xDC, 0xC2, 0xE7, 0xD4, 0xFA, 0xD6,
+ 0x19, 0x21, 0x29, 0xAE, 0x5E, 0xF4, 0x38, 0x81, 0xC6, 0x9E, 0x0E, 0x3C,
+ 0xCD, 0xC0, 0xDC, 0x93, 0x5D, 0xFD, 0x9A, 0x5C, 0xAB, 0x54, 0x1F, 0xFF,
+ 0x9C, 0x12, 0x1B, 0x4C, 0xDF, 0x2D, 0x9C, 0x85, 0xF9, 0x68, 0x15, 0x89,
+ 0x42, 0x9B, 0x6C, 0x45, 0x89, 0x3A, 0xBC, 0xE9, 0x19, 0x91, 0xBE, 0x0C,
+ 0xEF, 0x90, 0xCC, 0xF6, 0xD6, 0xF0, 0x3D, 0x5C, 0xF5, 0xE5, 0x0F, 0x2F,
+ 0x02, 0x8A, 0x83, 0x4B, 0x93, 0x2F, 0x14, 0x12, 0x1F, 0x56, 0x9A, 0x12,
+ 0x58, 0x88, 0xAE, 0x60, 0xB8, 0x5A, 0xE4, 0xA1, 0xBF, 0x4A, 0x81, 0x84,
+ 0xAB, 0xBB, 0xE4, 0xD0, 0x1D, 0x41, 0xD9, 0x0A, 0xAB, 0x1E, 0x47, 0x5B,
+ 0x31, 0xAC, 0x2B, 0x73
+};
+
+static unsigned char G2048[] = {
+ 0x02
+};
+
+static void
+test_speed_modpow(void)
+{
+ uint32_t mx[65], mp[65], me[65], t1[65], t2[65], len;
+ unsigned char e[64];
+ int i;
+ long num;
+
+ len = br_int_decode(mp, sizeof mp / sizeof mp[0],
+ P2048, sizeof P2048);
+ if (len != 65) {
+ abort();
+ }
+ memset(e, 'P', sizeof e);
+ if (!br_int_decode(me, sizeof me / sizeof me[0], e, sizeof e)) {
+ abort();
+ }
+ if (!br_modint_decode(mx, mp, G2048, sizeof G2048)) {
+ abort();
+ }
+ for (i = 0; i < 10; i ++) {
+ br_modint_to_monty(mx, mp);
+ br_modint_montypow(mx, me, mp, t1, t2);
+ br_modint_from_monty(mx, mp);
+ }
+ num = 10;
+ for (;;) {
+ clock_t begin, end;
+ double tt;
+ long k;
+
+ begin = clock();
+ for (k = num; k > 0; k --) {
+ br_modint_to_monty(mx, mp);
+ br_modint_montypow(mx, me, mp, t1, t2);
+ br_modint_from_monty(mx, mp);
+ }
+ end = clock();
+ tt = (double)(end - begin) / CLOCKS_PER_SEC;
+ if (tt >= 2.0) {
+ printf("%-30s %8.2f exp/s\n", "pow[2048:256]",
+ (double)num / tt);
+ fflush(stdout);
+ return;
+ }
+ num <<= 1;
+ }
+}
+
+static void
+test_speed_moddiv(void)
+{
+ uint32_t mx[65], my[65], mp[65], t1[65], t2[65], t3[65], len;
+ unsigned char x[255], y[255];
+ int i;
+ long num;
+
+ len = br_int_decode(mp, sizeof mp / sizeof mp[0],
+ P2048, sizeof P2048);
+ if (len != 65) {
+ abort();
+ }
+ memset(x, 'T', sizeof x);
+ memset(y, 'P', sizeof y);
+ if (!br_modint_decode(mx, mp, x, sizeof x)) {
+ abort();
+ }
+ if (!br_modint_decode(my, mp, y, sizeof y)) {
+ abort();
+ }
+ for (i = 0; i < 10; i ++) {
+ br_modint_div(mx, my, mp, t1, t2, t3);
+ }
+ num = 10;
+ for (;;) {
+ clock_t begin, end;
+ double tt;
+ long k;
+
+ begin = clock();
+ for (k = num; k > 0; k --) {
+ br_modint_div(mx, my, mp, t1, t2, t3);
+ }
+ end = clock();
+ tt = (double)(end - begin) / CLOCKS_PER_SEC;
+ if (tt >= 2.0) {
+ printf("%-30s %8.2f div/s\n", "div[2048]",
+ (double)num / tt);
+ fflush(stdout);
+ return;
+ }
+ num <<= 1;
+ }
+}
+#endif
+
+#define STU(x) { test_speed_ ## x, #x }
+
+static const struct {
+ void (*fn)(void);
+ char *name;
+} tfns[] = {
+ STU(md5),
+ STU(sha1),
+ STU(sha256),
+ STU(sha512),
+
+ STU(aes128_big_cbcenc),
+ STU(aes128_big_cbcdec),
+ STU(aes192_big_cbcenc),
+ STU(aes192_big_cbcdec),
+ STU(aes256_big_cbcenc),
+ STU(aes256_big_cbcdec),
+ STU(aes128_big_ctr),
+ STU(aes192_big_ctr),
+ STU(aes256_big_ctr),
+
+ STU(aes128_small_cbcenc),
+ STU(aes128_small_cbcdec),
+ STU(aes192_small_cbcenc),
+ STU(aes192_small_cbcdec),
+ STU(aes256_small_cbcenc),
+ STU(aes256_small_cbcdec),
+ STU(aes128_small_ctr),
+ STU(aes192_small_ctr),
+ STU(aes256_small_ctr),
+
+ STU(aes128_ct_cbcenc),
+ STU(aes128_ct_cbcdec),
+ STU(aes192_ct_cbcenc),
+ STU(aes192_ct_cbcdec),
+ STU(aes256_ct_cbcenc),
+ STU(aes256_ct_cbcdec),
+ STU(aes128_ct_ctr),
+ STU(aes192_ct_ctr),
+ STU(aes256_ct_ctr),
+
+ STU(aes128_ct64_cbcenc),
+ STU(aes128_ct64_cbcdec),
+ STU(aes192_ct64_cbcenc),
+ STU(aes192_ct64_cbcdec),
+ STU(aes256_ct64_cbcenc),
+ STU(aes256_ct64_cbcdec),
+ STU(aes128_ct64_ctr),
+ STU(aes192_ct64_ctr),
+ STU(aes256_ct64_ctr),
+
+ STU(des_tab_cbcenc),
+ STU(des_tab_cbcdec),
+ STU(3des_tab_cbcenc),
+ STU(3des_tab_cbcdec),
+
+ STU(des_ct_cbcenc),
+ STU(des_ct_cbcdec),
+ STU(3des_ct_cbcenc),
+ STU(3des_ct_cbcdec),
+
+ STU(ghash_ctmul),
+ STU(ghash_ctmul32),
+ STU(ghash_ctmul64),
+
+ STU(rsa_i31),
+ STU(rsa_i32),
+ STU(ec_prime_i31),
+ STU(ecdsa_i31),
+
+ STU(i31)
+};
+
+static int
+eq_name(const char *s1, const char *s2)
+{
+ for (;;) {
+ int c1, c2;
+
+ for (;;) {
+ c1 = *s1 ++;
+ if (c1 >= 'A' && c1 <= 'Z') {
+ c1 += 'a' - 'A';
+ } else {
+ switch (c1) {
+ case '-': case '_': case '.': case ' ':
+ continue;
+ }
+ }
+ break;
+ }
+ for (;;) {
+ c2 = *s2 ++;
+ if (c2 >= 'A' && c2 <= 'Z') {
+ c2 += 'a' - 'A';
+ } else {
+ switch (c2) {
+ case '-': case '_': case '.': case ' ':
+ continue;
+ }
+ }
+ break;
+ }
+ if (c1 != c2) {
+ return 0;
+ }
+ if (c1 == 0) {
+ return 1;
+ }
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+ size_t u;
+
+ if (argc <= 1) {
+ printf("usage: testspeed all | name...\n");
+ printf("individual test names:\n");
+ for (u = 0; u < (sizeof tfns) / (sizeof tfns[0]); u ++) {
+ printf(" %s\n", tfns[u].name);
+ }
+ } else {
+ for (u = 0; u < (sizeof tfns) / (sizeof tfns[0]); u ++) {
+ int i;
+
+ for (i = 1; i < argc; i ++) {
+ if (eq_name(argv[i], tfns[u].name)
+ || eq_name(argv[i], "all"))
+ {
+ tfns[u].fn();
+ break;
+ }
+ }
+ }
+ }
+ return 0;
+}
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "bearssl.h"
+
+#define DIRNAME "test/x509"
+#define CONFFILE (DIRNAME "/alltests.txt")
+#define DEFAULT_TIME "2016-08-30T18:00:00Z"
+
+static void *
+xmalloc(size_t len)
+{
+ void *buf;
+
+ if (len == 0) {
+ return NULL;
+ }
+ buf = malloc(len);
+ if (buf == NULL) {
+ fprintf(stderr, "error: cannot allocate %lu byte(s)\n",
+ (unsigned long)len);
+ exit(EXIT_FAILURE);
+ }
+ return buf;
+}
+
+static void
+xfree(void *buf)
+{
+ if (buf != NULL) {
+ free(buf);
+ }
+}
+
+static char *
+xstrdup(const char *name)
+{
+ size_t n;
+ char *s;
+
+ if (name == NULL) {
+ return NULL;
+ }
+ n = strlen(name) + 1;
+ s = xmalloc(n);
+ memcpy(s, name, n);
+ return s;
+}
+
+typedef struct {
+ char *buf;
+ size_t ptr, len;
+} string_builder;
+
+static string_builder *
+SB_new(void)
+{
+ string_builder *sb;
+
+ sb = xmalloc(sizeof *sb);
+ sb->len = 8;
+ sb->buf = xmalloc(sb->len);
+ sb->ptr = 0;
+ return sb;
+}
+
+static void
+SB_expand(string_builder *sb, size_t extra_len)
+{
+ size_t nlen;
+ char *nbuf;
+
+ if (extra_len < (sb->len - sb->ptr)) {
+ return;
+ }
+ nlen = sb->len << 1;
+ if (extra_len > (nlen - sb->ptr)) {
+ nlen = sb->ptr + extra_len;
+ }
+ nbuf = xmalloc(nlen);
+ memcpy(nbuf, sb->buf, sb->ptr);
+ xfree(sb->buf);
+ sb->buf = nbuf;
+ sb->len = nlen;
+}
+
+static void
+SB_append_char(string_builder *sb, int c)
+{
+ SB_expand(sb, 1);
+ sb->buf[sb->ptr ++] = c;
+}
+
+/* unused
+static void
+SB_append_string(string_builder *sb, const char *s)
+{
+ size_t n;
+
+ n = strlen(s);
+ SB_expand(sb, n);
+ memcpy(sb->buf + sb->ptr, s, n);
+ sb->ptr += n;
+}
+*/
+
+/* unused
+static char *
+SB_to_string(string_builder *sb)
+{
+ char *s;
+
+ s = xmalloc(sb->ptr + 1);
+ memcpy(s, sb->buf, sb->ptr);
+ s[sb->ptr] = 0;
+ return s;
+}
+*/
+
+static char *
+SB_contents(string_builder *sb)
+{
+ return sb->buf;
+}
+
+static size_t
+SB_length(string_builder *sb)
+{
+ return sb->ptr;
+}
+
+static void
+SB_set_length(string_builder *sb, size_t len)
+{
+ if (sb->ptr < len) {
+ SB_expand(sb, len - sb->ptr);
+ memset(sb->buf + sb->ptr, ' ', len - sb->ptr);
+ }
+ sb->ptr = len;
+}
+
+static void
+SB_reset(string_builder *sb)
+{
+ SB_set_length(sb, 0);
+}
+
+static void
+SB_free(string_builder *sb)
+{
+ xfree(sb->buf);
+ xfree(sb);
+}
+
+typedef struct ht_elt_ {
+ char *name;
+ void *value;
+ struct ht_elt_ *next;
+} ht_elt;
+
+typedef struct {
+ size_t size;
+ ht_elt **buckets;
+ size_t num_buckets;
+} HT;
+
+static HT *
+HT_new(void)
+{
+ HT *ht;
+ size_t u;
+
+ ht = xmalloc(sizeof *ht);
+ ht->size = 0;
+ ht->num_buckets = 8;
+ ht->buckets = xmalloc(ht->num_buckets * sizeof(ht_elt *));
+ for (u = 0; u < ht->num_buckets; u ++) {
+ ht->buckets[u] = NULL;
+ }
+ return ht;
+}
+
+static uint32_t
+hash_string(const char *name)
+{
+ uint32_t hc;
+
+ hc = 0;
+ while (*name) {
+ int x;
+
+ hc = (hc << 5) - hc;
+ x = *(const unsigned char *)name;
+ if (x >= 'A' && x <= 'Z') {
+ x += 'a' - 'A';
+ }
+ hc += (uint32_t)x;
+ name ++;
+ }
+ return hc;
+}
+
+static int
+eqstring(const char *s1, const char *s2)
+{
+ while (*s1 && *s2) {
+ int x1, x2;
+
+ x1 = *(const unsigned char *)s1;
+ x2 = *(const unsigned char *)s2;
+ if (x1 >= 'A' && x1 <= 'Z') {
+ x1 += 'a' - 'A';
+ }
+ if (x2 >= 'A' && x2 <= 'Z') {
+ x2 += 'a' - 'A';
+ }
+ if (x1 != x2) {
+ return 0;
+ }
+ s1 ++;
+ s2 ++;
+ }
+ return !(*s1 || *s2);
+}
+
+static void
+HT_expand(HT *ht)
+{
+ size_t n, n2, u;
+ ht_elt **new_buckets;
+
+ n = ht->num_buckets;
+ n2 = n << 1;
+ new_buckets = xmalloc(n2 * sizeof *new_buckets);
+ for (u = 0; u < n; u ++) {
+ ht_elt *e, *f;
+
+ f = NULL;
+ for (e = ht->buckets[u]; e != NULL; e = f) {
+ uint32_t hc;
+ size_t v;
+
+ hc = hash_string(e->name);
+ v = (size_t)(hc & ((uint32_t)n2 - 1));
+ f = e->next;
+ e->next = new_buckets[v];
+ new_buckets[v] = e;
+ }
+ }
+ xfree(ht->buckets);
+ ht->buckets = new_buckets;
+ ht->num_buckets = n2;
+}
+
+static void *
+HT_put(HT *ht, const char *name, void *value)
+{
+ uint32_t hc;
+ size_t k;
+ ht_elt *e, **prev;
+
+ hc = hash_string(name);
+ k = (size_t)(hc & ((uint32_t)ht->num_buckets - 1));
+ prev = &ht->buckets[k];
+ e = *prev;
+ while (e != NULL) {
+ if (eqstring(name, e->name)) {
+ void *old_value;
+
+ old_value = e->value;
+ if (value == NULL) {
+ *prev = e->next;
+ xfree(e->name);
+ xfree(e);
+ ht->size --;
+ } else {
+ e->value = value;
+ }
+ return old_value;
+ }
+ prev = &e->next;
+ e = *prev;
+ }
+ if (value != NULL) {
+ e = xmalloc(sizeof *e);
+ e->name = xstrdup(name);
+ e->value = value;
+ e->next = ht->buckets[k];
+ ht->buckets[k] = e;
+ ht->size ++;
+ if (ht->size > ht->num_buckets) {
+ HT_expand(ht);
+ }
+ }
+ return NULL;
+}
+
+/* unused
+static void *
+HT_remove(HT *ht, const char *name)
+{
+ return HT_put(ht, name, NULL);
+}
+*/
+
+static void *
+HT_get(const HT *ht, const char *name)
+{
+ uint32_t hc;
+ size_t k;
+ ht_elt *e;
+
+ hc = hash_string(name);
+ k = (size_t)(hc & ((uint32_t)ht->num_buckets - 1));
+ for (e = ht->buckets[k]; e != NULL; e = e->next) {
+ if (eqstring(name, e->name)) {
+ return e->value;
+ }
+ }
+ return NULL;
+}
+
+static void
+HT_clear(HT *ht, void (*free_value)(void *value))
+{
+ size_t u;
+
+ for (u = 0; u < ht->num_buckets; u ++) {
+ ht_elt *e, *f;
+
+ f = NULL;
+ for (e = ht->buckets[u]; e != NULL; e = f) {
+ f = e->next;
+ xfree(e->name);
+ if (free_value != 0) {
+ free_value(e->value);
+ }
+ xfree(e);
+ }
+ ht->buckets[u] = NULL;
+ }
+ ht->size = 0;
+}
+
+static void
+HT_free(HT *ht, void (*free_value)(void *value))
+{
+ HT_clear(ht, free_value);
+ xfree(ht->buckets);
+ xfree(ht);
+}
+
+/* unused
+static size_t
+HT_size(HT *ht)
+{
+ return ht->size;
+}
+*/
+
+static unsigned char *
+read_all(FILE *f, size_t *len)
+{
+ unsigned char *buf;
+ size_t ptr, blen;
+
+ blen = 1024;
+ buf = xmalloc(blen);
+ ptr = 0;
+ for (;;) {
+ size_t rlen;
+
+ if (ptr == blen) {
+ unsigned char *buf2;
+
+ blen <<= 1;
+ buf2 = xmalloc(blen);
+ memcpy(buf2, buf, ptr);
+ xfree(buf);
+ buf = buf2;
+ }
+ rlen = fread(buf + ptr, 1, blen - ptr, f);
+ if (rlen == 0) {
+ unsigned char *buf3;
+
+ buf3 = xmalloc(ptr);
+ memcpy(buf3, buf, ptr);
+ xfree(buf);
+ *len = ptr;
+ return buf3;
+ }
+ ptr += rlen;
+ }
+}
+
+static unsigned char *
+read_file(const char *name, size_t *len)
+{
+ FILE *f;
+ unsigned char *buf;
+
+#ifdef DIRNAME
+ char *dname;
+
+ dname = xmalloc(strlen(DIRNAME) + strlen(name) + 2);
+ sprintf(dname, "%s/%s", DIRNAME, name);
+ name = dname;
+#endif
+ f = fopen(name, "rb");
+ if (f == NULL) {
+ fprintf(stderr, "could not open file '%s'\n", name);
+ exit(EXIT_FAILURE);
+ }
+ buf = read_all(f, len);
+ if (ferror(f)) {
+ fprintf(stderr, "read error on file '%s'\n", name);
+ exit(EXIT_FAILURE);
+ }
+ fclose(f);
+#ifdef DIRNAME
+ xfree(dname);
+#endif
+ return buf;
+}
+
+static int
+parse_dec(const char *s, unsigned len, int *val)
+{
+ int acc;
+
+ acc = 0;
+ while (len -- > 0) {
+ int c;
+
+ c = *s ++;
+ if (c >= '0' && c <= '9') {
+ acc = (acc * 10) + (c - '0');
+ } else {
+ return -1;
+ }
+ }
+ *val = acc;
+ return 0;
+}
+
+static int
+parse_choice(const char *s, const char *acceptable)
+{
+ int c;
+
+ c = *s;
+ while (*acceptable) {
+ if (c == *acceptable ++) {
+ return 0;
+ }
+ }
+ return -1;
+}
+
+static int
+month_length(int year, int month)
+{
+ static const int base_month_length[] = {
+ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+ };
+
+ int x;
+
+ x = base_month_length[month - 1];
+ if (month == 2 && year % 4 == 0
+ && (year % 100 != 0 || year % 400 == 0))
+ {
+ x ++;
+ }
+ return x;
+}
+
+/*
+ * Convert a time string to a days+seconds count. Returned value is 0
+ * on success, -1 on error.
+ */
+static int
+string_to_time(const char *s, uint32_t *days, uint32_t *seconds)
+{
+ int year, month, day, hour, minute, second;
+ int day_of_year, leaps;
+
+ if (parse_dec(s, 4, &year) < 0) {
+ return -1;
+ }
+ s += 4;
+ if (parse_choice(s ++, "-:/ ") < 0) {
+ return -1;
+ }
+ if (parse_dec(s, 2, &month) < 0) {
+ return -1;
+ }
+ s += 2;
+ if (parse_choice(s ++, "-:/ ") < 0) {
+ return -1;
+ }
+ if (parse_dec(s, 2, &day) < 0) {
+ return -1;
+ }
+ s += 2;
+ if (parse_choice(s ++, " T") < 0) {
+ return -1;
+ }
+ if (parse_dec(s, 2, &hour) < 0) {
+ return -1;
+ }
+ s += 2;
+ if (parse_choice(s ++, "-:/ ") < 0) {
+ return -1;
+ }
+ if (parse_dec(s, 2, &minute) < 0) {
+ return -1;
+ }
+ s += 2;
+ if (parse_choice(s ++, "-:/ ") < 0) {
+ return -1;
+ }
+ if (parse_dec(s, 2, &second) < 0) {
+ return -1;
+ }
+ s += 2;
+ if (*s == '.') {
+ while (*s && *s >= '0' && *s <= '9') {
+ s ++;
+ }
+ }
+ if (*s) {
+ if (*s ++ != 'Z') {
+ return -1;
+ }
+ if (*s) {
+ return -1;
+ }
+ }
+
+ if (month < 1 || month > 12) {
+ return -1;
+ }
+ day_of_year = 0;
+ for (int i = 1; i < month; i ++) {
+ day_of_year += month_length(year, i);
+ }
+ if (day < 1 || day > month_length(year, month)) {
+ return -1;
+ }
+ day_of_year += (day - 1);
+ leaps = (year + 3) / 4 - (year + 99) / 100 + (year + 399) / 400;
+
+ if (hour > 23 || minute > 59 || second > 60) {
+ return -1;
+ }
+ *days = (uint32_t)year * 365 + (uint32_t)leaps + day_of_year;
+ *seconds = (uint32_t)hour * 3600 + minute * 60 + second;
+ return 0;
+}
+
+static FILE *conf;
+static int conf_delayed_char;
+static long conf_linenum;
+static string_builder *line_builder;
+static long current_linenum;
+
+static void
+conf_init(const char *fname)
+{
+ conf = fopen(fname, "r");
+ if (conf == NULL) {
+ fprintf(stderr, "could not open file '%s'\n", fname);
+ exit(EXIT_FAILURE);
+ }
+ conf_delayed_char = -1;
+ conf_linenum = 1;
+ line_builder = SB_new();
+}
+
+static void
+conf_close(void)
+{
+ if (conf != NULL) {
+ if (ferror(conf)) {
+ fprintf(stderr, "read error on configuration file\n");
+ exit(EXIT_FAILURE);
+ }
+ fclose(conf);
+ conf = NULL;
+ }
+ if (line_builder != NULL) {
+ SB_free(line_builder);
+ line_builder = NULL;
+ }
+}
+
+/*
+ * Get next character from the config file.
+ */
+static int
+conf_next_low(void)
+{
+ int x;
+
+ x = conf_delayed_char;
+ if (x >= 0) {
+ conf_delayed_char = -1;
+ } else {
+ x = fgetc(conf);
+ if (x == EOF) {
+ x = -1;
+ }
+ }
+ if (x == '\r') {
+ x = fgetc(conf);
+ if (x == EOF) {
+ x = -1;
+ }
+ if (x != '\n') {
+ conf_delayed_char = x;
+ x = '\n';
+ }
+ }
+ if (x == '\n') {
+ conf_linenum ++;
+ }
+ return x;
+}
+
+static int
+is_ws(int x)
+{
+ return x <= 32;
+}
+
+static int
+is_name_char(int c)
+{
+ return (c >= 'A' && c <= 'Z')
+ || (c >= 'a' && c <= 'z')
+ || (c >= '0' && c <= '9')
+ || (c == '_' || c == '-' || c == '.');
+}
+
+/*
+ * Read a complete line. This handles line continuation; empty lines and
+ * comment lines are skipped; leading and trailing whitespace is removed.
+ * Returned value is 0 (line read) or -1 (no line, EOF reached). The line
+ * contents are accumulated in the line_builder.
+ */
+static int
+conf_next_line(void)
+{
+ for (;;) {
+ int c;
+ int lcwb;
+
+ SB_reset(line_builder);
+
+ /*
+ * Get first non-whitespace character. This skips empty
+ * lines. Comment lines (first non-whitespace character
+ * is a semicolon) are also skipped.
+ */
+ for (;;) {
+ c = conf_next_low();
+ if (c < 0) {
+ return -1;
+ }
+ if (is_ws(c)) {
+ continue;
+ }
+ if (c == ';') {
+ for (;;) {
+ c = conf_next_low();
+ if (c < 0) {
+ return -1;
+ }
+ if (c == '\n') {
+ break;
+ }
+ }
+ continue;
+ }
+ break;
+ }
+
+ /*
+ * Read up the remaining of the line. The line continuation
+ * sequence (final backslash) is detected and processed.
+ */
+ current_linenum = conf_linenum;
+ lcwb = (c == '\\');
+ SB_append_char(line_builder, c);
+ for (;;) {
+ c = conf_next_low();
+ if (c < 0) {
+ break;
+ }
+ if (lcwb) {
+ if (c == '\n') {
+ SB_set_length(line_builder,
+ SB_length(line_builder) - 1);
+ }
+ lcwb = 0;
+ continue;
+ }
+ if (c == '\n') {
+ break;
+ } else if (c == '\\') {
+ lcwb = 1;
+ }
+ SB_append_char(line_builder, c);
+ }
+
+ /*
+ * Remove trailing whitespace (if any).
+ */
+ for (;;) {
+ size_t u;
+
+ u = SB_length(line_builder);
+ if (u == 0 || !is_ws(
+ SB_contents(line_builder)[u - 1]))
+ {
+ break;
+ }
+ SB_set_length(line_builder, u - 1);
+ }
+
+ /*
+ * We might end up with a totally empty line (in case there
+ * was a line continuation but nothing else), in which case
+ * we must loop.
+ */
+ if (SB_length(line_builder) > 0) {
+ return 0;
+ }
+ }
+}
+
+/*
+ * Test whether the current line is a section header. If yes, then the
+ * header name is extracted, and returned as a newly allocated string.
+ * Otherwise, NULL is returned.
+ */
+static char *
+parse_header_name(void)
+{
+ char *buf, *name;
+ size_t u, v, w, len;
+
+ buf = SB_contents(line_builder);
+ len = SB_length(line_builder);
+ if (len < 2 || buf[0] != '[' || buf[len - 1] != ']') {
+ return NULL;
+ }
+ u = 1;
+ v = len - 1;
+ while (u < v && is_ws(buf[u])) {
+ u ++;
+ }
+ while (u < v && is_ws(buf[v - 1])) {
+ v --;
+ }
+ if (u == v) {
+ return NULL;
+ }
+ for (w = u; w < v; w ++) {
+ if (!is_name_char(buf[w])) {
+ return NULL;
+ }
+ }
+ len = v - u;
+ name = xmalloc(len + 1);
+ memcpy(name, buf + u, len);
+ name[len] = 0;
+ return name;
+}
+
+/*
+ * Parse the current line as a 'name = value' pair. The pair is pushed into
+ * the provided hash table. On error (including a duplicate key name),
+ * this function returns -1; otherwise, it returns 0.
+ */
+static int
+parse_keyvalue(HT *d)
+{
+ char *buf, *name, *value;
+ size_t u, len;
+
+ buf = SB_contents(line_builder);
+ len = SB_length(line_builder);
+ for (u = 0; u < len; u ++) {
+ if (!is_name_char(buf[u])) {
+ break;
+ }
+ }
+ if (u == 0) {
+ return -1;
+ }
+ name = xmalloc(u + 1);
+ memcpy(name, buf, u);
+ name[u] = 0;
+ if (HT_get(d, name) != NULL) {
+ xfree(name);
+ return -1;
+ }
+ while (u < len && is_ws(buf[u])) {
+ u ++;
+ }
+ if (u >= len || buf[u] != '=') {
+ xfree(name);
+ return -1;
+ }
+ u ++;
+ while (u < len && is_ws(buf[u])) {
+ u ++;
+ }
+ value = xmalloc(len - u + 1);
+ memcpy(value, buf + u, len - u);
+ value[len - u] = 0;
+ HT_put(d, name, value);
+ xfree(name);
+ return 0;
+}
+
+/*
+ * Public keys, indexed by name. Elements are pointers to br_x509_pkey
+ * structures.
+ */
+static HT *keys;
+
+/*
+ * Trust anchors, indexed by name. Elements are pointers to
+ * test_trust_anchor structures.
+ */
+static HT *trust_anchors;
+
+typedef struct {
+ unsigned char *dn;
+ size_t dn_len;
+ unsigned flags;
+ char *key_name;
+} test_trust_anchor;
+
+/*
+ * Test case: trust anchors, certificates (file names), key type and
+ * usage, expected status and EE public key.
+ */
+typedef struct {
+ char *name;
+ char **ta_names;
+ char **cert_names;
+ char *servername;
+ unsigned key_type_usage;
+ unsigned status;
+ char *ee_key_name;
+ unsigned hashes;
+ uint32_t days, seconds;
+} test_case;
+
+static test_case *all_chains;
+static size_t all_chains_ptr, all_chains_len;
+
+static void
+free_key(void *value)
+{
+ br_x509_pkey *pk;
+
+ pk = value;
+ switch (pk->key_type) {
+ case BR_KEYTYPE_RSA:
+ xfree((void *)pk->key.rsa.n);
+ xfree((void *)pk->key.rsa.e);
+ break;
+ case BR_KEYTYPE_EC:
+ xfree((void *)pk->key.ec.q);
+ break;
+ default:
+ fprintf(stderr, "unknown key type: %d\n", pk->key_type);
+ exit(EXIT_FAILURE);
+ break;
+ }
+ xfree(pk);
+}
+
+static void
+free_trust_anchor(void *value)
+{
+ test_trust_anchor *ttc;
+
+ ttc = value;
+ xfree(ttc->dn);
+ xfree(ttc->key_name);
+ xfree(ttc);
+}
+
+static void
+free_test_case_contents(test_case *tc)
+{
+ size_t u;
+
+ xfree(tc->name);
+ for (u = 0; tc->ta_names[u]; u ++) {
+ xfree(tc->ta_names[u]);
+ }
+ xfree(tc->ta_names);
+ for (u = 0; tc->cert_names[u]; u ++) {
+ xfree(tc->cert_names[u]);
+ }
+ xfree(tc->cert_names);
+ xfree(tc->servername);
+ xfree(tc->ee_key_name);
+}
+
+static char *
+get_value(char *objtype, HT *objdata, long linenum, char *name)
+{
+ char *value;
+
+ value = HT_get(objdata, name);
+ if (value == NULL) {
+ fprintf(stderr,
+ "missing property '%s' in section '%s' (line %ld)\n",
+ name, objtype, linenum);
+ exit(EXIT_FAILURE);
+ }
+ return value;
+}
+
+static unsigned char *
+parse_hex(const char *name, long linenum, const char *value, size_t *len)
+{
+ unsigned char *buf;
+
+ buf = NULL;
+ for (;;) {
+ size_t u, ptr;
+ int acc, z;
+
+ ptr = 0;
+ acc = 0;
+ z = 0;
+ for (u = 0; value[u]; u ++) {
+ int c;
+
+ c = value[u];
+ if (c >= '0' && c <= '9') {
+ c -= '0';
+ } else if (c >= 'A' && c <= 'F') {
+ c -= 'A' - 10;
+ } else if (c >= 'a' && c <= 'f') {
+ c -= 'a' - 10;
+ } else if (c == ' ' || c == ':') {
+ continue;
+ } else {
+ fprintf(stderr, "invalid hexadecimal character"
+ " in '%s' (line %ld)\n",
+ name, linenum);
+ exit(EXIT_FAILURE);
+ }
+ if (z) {
+ if (buf != NULL) {
+ buf[ptr] = (acc << 4) + c;
+ }
+ ptr ++;
+ } else {
+ acc = c;
+ }
+ z = !z;
+ }
+ if (z) {
+ fprintf(stderr, "invalid hexadecimal value (partial"
+ " byte) in '%s' (line %ld)\n",
+ name, linenum);
+ exit(EXIT_FAILURE);
+ }
+ if (buf == NULL) {
+ buf = xmalloc(ptr);
+ } else {
+ *len = ptr;
+ return buf;
+ }
+ }
+}
+
+static char **
+split_names(const char *value)
+{
+ char **names;
+ size_t len;
+
+ names = NULL;
+ len = strlen(value);
+ for (;;) {
+ size_t u, ptr;
+
+ ptr = 0;
+ u = 0;
+ while (u < len) {
+ size_t v;
+
+ while (u < len && is_ws(value[u])) {
+ u ++;
+ }
+ v = u;
+ while (v < len && !is_ws(value[v])) {
+ v ++;
+ }
+ if (v > u) {
+ if (names != NULL) {
+ char *name;
+
+ name = xmalloc(v - u + 1);
+ memcpy(name, value + u, v - u);
+ name[v - u] = 0;
+ names[ptr] = name;
+ }
+ ptr ++;
+ }
+ u = v;
+ }
+ if (names == NULL) {
+ names = xmalloc((ptr + 1) * sizeof *names);
+ } else {
+ names[ptr] = NULL;
+ return names;
+ }
+ }
+}
+
+static int
+string_to_hash(const char *name)
+{
+ char tmp[20];
+ size_t u, v;
+
+ for (u = 0, v = 0; name[u]; u ++) {
+ int c;
+
+ c = name[u];
+ if ((c >= '0' && c <= '9')
+ || (c >= 'A' && c <= 'Z')
+ || (c >= 'a' && c <= 'z'))
+ {
+ tmp[v ++] = c;
+ if (v == sizeof tmp) {
+ return -1;
+ }
+ }
+ }
+ tmp[v] = 0;
+ if (eqstring(tmp, "md5")) {
+ return br_md5_ID;
+ } else if (eqstring(tmp, "sha1")) {
+ return br_sha1_ID;
+ } else if (eqstring(tmp, "sha224")) {
+ return br_sha224_ID;
+ } else if (eqstring(tmp, "sha256")) {
+ return br_sha256_ID;
+ } else if (eqstring(tmp, "sha384")) {
+ return br_sha384_ID;
+ } else if (eqstring(tmp, "sha512")) {
+ return br_sha512_ID;
+ } else {
+ return -1;
+ }
+}
+
+static int
+string_to_curve(const char *name)
+{
+ char tmp[20];
+ size_t u, v;
+
+ for (u = 0, v = 0; name[u]; u ++) {
+ int c;
+
+ c = name[u];
+ if ((c >= '0' && c <= '9')
+ || (c >= 'A' && c <= 'Z')
+ || (c >= 'a' && c <= 'z'))
+ {
+ tmp[v ++] = c;
+ if (v == sizeof tmp) {
+ return -1;
+ }
+ }
+ }
+ tmp[v] = 0;
+ if (eqstring(tmp, "p256") || eqstring(tmp, "secp256r1")) {
+ return BR_EC_secp256r1;
+ } else if (eqstring(tmp, "p384") || eqstring(tmp, "secp384r1")) {
+ return BR_EC_secp384r1;
+ } else if (eqstring(tmp, "p521") || eqstring(tmp, "secp521r1")) {
+ return BR_EC_secp521r1;
+ } else {
+ return -1;
+ }
+}
+
+static void
+parse_object(char *objtype, HT *objdata, long linenum)
+{
+ char *name;
+
+ name = get_value(objtype, objdata, linenum, "name");
+ if (eqstring(objtype, "key")) {
+ char *stype;
+ br_x509_pkey *pk;
+
+ stype = get_value(objtype, objdata, linenum, "type");
+ pk = xmalloc(sizeof *pk);
+ if (eqstring(stype, "RSA")) {
+ char *sn, *se;
+
+ sn = get_value(objtype, objdata, linenum, "n");
+ se = get_value(objtype, objdata, linenum, "e");
+ pk->key_type = BR_KEYTYPE_RSA;
+ pk->key.rsa.n = parse_hex("modulus", linenum,
+ sn, &pk->key.rsa.nlen);
+ pk->key.rsa.e = parse_hex("exponent", linenum,
+ se, &pk->key.rsa.elen);
+ } else if (eqstring(stype, "EC")) {
+ char *sc, *sq;
+ int curve;
+
+ sc = get_value(objtype, objdata, linenum, "curve");
+ sq = get_value(objtype, objdata, linenum, "q");
+ curve = string_to_curve(sc);
+ if (curve < 0) {
+ fprintf(stderr, "unknown curve name: '%s'"
+ " (line %ld)\n", sc, linenum);
+ exit(EXIT_FAILURE);
+ }
+ pk->key_type = BR_KEYTYPE_EC;
+ pk->key.ec.curve = curve;
+ pk->key.ec.q = parse_hex("public point", linenum,
+ sq, &pk->key.ec.qlen);
+ } else {
+ fprintf(stderr, "unknown key type '%s' (line %ld)\n",
+ stype, linenum);
+ exit(EXIT_FAILURE);
+ }
+ if (HT_put(keys, name, pk) != NULL) {
+ fprintf(stderr, "duplicate key: '%s' (line %ld)\n",
+ name, linenum);
+ exit(EXIT_FAILURE);
+ }
+ } else if (eqstring(objtype, "anchor")) {
+ char *dnfile, *kname, *tatype;
+ test_trust_anchor *tta;
+
+ dnfile = get_value(objtype, objdata, linenum, "DN_file");
+ kname = get_value(objtype, objdata, linenum, "key");
+ tatype = get_value(objtype, objdata, linenum, "type");
+ tta = xmalloc(sizeof *tta);
+ tta->dn = read_file(dnfile, &tta->dn_len);
+ tta->key_name = xstrdup(kname);
+ if (eqstring(tatype, "CA")) {
+ tta->flags = BR_X509_TA_CA;
+ } else if (eqstring(tatype, "EE")) {
+ tta->flags = 0;
+ } else {
+ fprintf(stderr,
+ "unknown trust anchor type: '%s' (line %ld)\n",
+ tatype, linenum);
+ }
+ if (HT_put(trust_anchors, name, tta) != NULL) {
+ fprintf(stderr,
+ "duplicate trust anchor: '%s' (line %ld)\n",
+ name, linenum);
+ exit(EXIT_FAILURE);
+ }
+ } else if (eqstring(objtype, "chain")) {
+ test_case tc;
+ char *ktype, *kusage, *sstatus, *shashes, *stime;
+
+ ktype = get_value(objtype, objdata, linenum, "keytype");
+ kusage = get_value(objtype, objdata, linenum, "keyusage");
+ sstatus = get_value(objtype, objdata, linenum, "status");
+ tc.name = xstrdup(name);
+ tc.ta_names = split_names(
+ get_value(objtype, objdata, linenum, "anchors"));
+ tc.cert_names = split_names(
+ get_value(objtype, objdata, linenum, "chain"));
+ tc.servername = xstrdup(HT_get(objdata, "servername"));
+ if (eqstring(ktype, "RSA")) {
+ tc.key_type_usage = BR_KEYTYPE_RSA;
+ } else if (eqstring(ktype, "EC")) {
+ tc.key_type_usage = BR_KEYTYPE_EC;
+ } else {
+ fprintf(stderr,
+ "unknown key type: '%s' (line %ld)\n",
+ ktype, linenum);
+ exit(EXIT_FAILURE);
+ }
+ if (eqstring(kusage, "KEYX")) {
+ tc.key_type_usage |= BR_KEYTYPE_KEYX;
+ } else if (eqstring(kusage, "SIGN")) {
+ tc.key_type_usage |= BR_KEYTYPE_SIGN;
+ } else {
+ fprintf(stderr,
+ "unknown key usage: '%s' (line %ld)\n",
+ kusage, linenum);
+ exit(EXIT_FAILURE);
+ }
+ tc.status = (unsigned)atoi(sstatus);
+ if (tc.status == 0) {
+ tc.ee_key_name = xstrdup(
+ get_value(objtype, objdata, linenum, "eekey"));
+ } else {
+ tc.ee_key_name = NULL;
+ }
+ shashes = HT_get(objdata, "hashes");
+ if (shashes == NULL) {
+ tc.hashes = (unsigned)-1;
+ } else {
+ char **hns;
+ size_t u;
+
+ tc.hashes = 0;
+ hns = split_names(shashes);
+ for (u = 0;; u ++) {
+ char *hn;
+ int id;
+
+ hn = hns[u];
+ if (hn == NULL) {
+ break;
+ }
+ id = string_to_hash(hn);
+ if (id < 0) {
+ fprintf(stderr,
+ "unknown hash function '%s'"
+ " (line %ld)\n", hn, linenum);
+ exit(EXIT_FAILURE);
+ }
+ tc.hashes |= (unsigned)1 << id;
+ xfree(hn);
+ }
+ xfree(hns);
+ }
+ stime = HT_get(objdata, "time");
+ if (stime == NULL) {
+ stime = DEFAULT_TIME;
+ }
+ if (string_to_time(stime, &tc.days, &tc.seconds) < 0) {
+ fprintf(stderr, "invalid time string '%s' (line %ld)\n",
+ stime, linenum);
+ exit(EXIT_FAILURE);
+ }
+ if (all_chains_ptr == all_chains_len) {
+ if (all_chains_len == 0) {
+ all_chains_len = 8;
+ all_chains = xmalloc(
+ all_chains_len * sizeof *all_chains);
+ } else {
+ test_case *ntc;
+ size_t nlen;
+
+ nlen = all_chains_len << 1;
+ ntc = xmalloc(nlen * sizeof *ntc);
+ memcpy(ntc, all_chains,
+ all_chains_len * sizeof *all_chains);
+ xfree(all_chains);
+ all_chains = ntc;
+ all_chains_len = nlen;
+ }
+ }
+ all_chains[all_chains_ptr ++] = tc;
+ } else {
+ fprintf(stderr, "unknown section type '%s' (line %ld)\n",
+ objtype, linenum);
+ exit(EXIT_FAILURE);
+ }
+}
+
+static void
+process_conf_file(const char *fname)
+{
+ char *objtype;
+ HT *objdata;
+ long objlinenum;
+
+ keys = HT_new();
+ trust_anchors = HT_new();
+ all_chains = NULL;
+ all_chains_ptr = 0;
+ all_chains_len = 0;
+ conf_init(fname);
+ objtype = NULL;
+ objdata = HT_new();
+ objlinenum = 0;
+ for (;;) {
+ char *hname;
+
+ if (conf_next_line() < 0) {
+ break;
+ }
+ hname = parse_header_name();
+ if (hname != NULL) {
+ if (objtype != NULL) {
+ parse_object(objtype, objdata, objlinenum);
+ HT_clear(objdata, xfree);
+ xfree(objtype);
+ }
+ objtype = hname;
+ objlinenum = current_linenum;
+ continue;
+ }
+ if (objtype == NULL) {
+ fprintf(stderr, "no current section (line %ld)\n",
+ current_linenum);
+ exit(EXIT_FAILURE);
+ }
+ if (parse_keyvalue(objdata) < 0) {
+ fprintf(stderr, "wrong configuration, line %ld\n",
+ current_linenum);
+ exit(EXIT_FAILURE);
+ }
+ }
+ if (objtype != NULL) {
+ parse_object(objtype, objdata, objlinenum);
+ xfree(objtype);
+ }
+ HT_free(objdata, xfree);
+ conf_close();
+}
+
+static const struct {
+ int id;
+ const br_hash_class *impl;
+} hash_impls[] = {
+ { br_md5_ID, &br_md5_vtable },
+ { br_sha1_ID, &br_sha1_vtable },
+ { br_sha224_ID, &br_sha224_vtable },
+ { br_sha256_ID, &br_sha256_vtable },
+ { br_sha384_ID, &br_sha384_vtable },
+ { br_sha512_ID, &br_sha512_vtable },
+ { 0, NULL }
+};
+
+typedef struct {
+ unsigned char *data;
+ size_t len;
+} blob;
+
+static int
+eqbigint(const unsigned char *b1, size_t b1_len,
+ const unsigned char *b2, size_t b2_len)
+{
+ while (b1_len > 0 && *b1 == 0) {
+ b1 ++;
+ b1_len --;
+ }
+ while (b2_len > 0 && *b2 == 0) {
+ b2 ++;
+ b2_len --;
+ }
+ return b1_len == b2_len && memcmp(b1, b2, b1_len) == 0;
+}
+
+static int
+eqpkey(const br_x509_pkey *pk1, const br_x509_pkey *pk2)
+{
+ if (pk1 == pk2) {
+ return 1;
+ }
+ if (pk1 == NULL || pk2 == NULL) {
+ return 0;
+ }
+ if (pk1->key_type != pk2->key_type) {
+ return 0;
+ }
+ switch (pk1->key_type) {
+ case BR_KEYTYPE_RSA:
+ return eqbigint(pk1->key.rsa.n, pk1->key.rsa.nlen,
+ pk2->key.rsa.n, pk2->key.rsa.nlen)
+ && eqbigint(pk1->key.rsa.e, pk1->key.rsa.elen,
+ pk2->key.rsa.e, pk2->key.rsa.elen);
+ case BR_KEYTYPE_EC:
+ return pk1->key.ec.curve == pk2->key.ec.curve
+ && pk1->key.ec.qlen == pk2->key.ec.qlen
+ && memcmp(pk1->key.ec.q,
+ pk2->key.ec.q, pk1->key.ec.qlen) == 0;
+ default:
+ fprintf(stderr, "unknown key type: %d\n", pk1->key_type);
+ exit(EXIT_FAILURE);
+ break;
+ }
+ return 0;
+}
+
+static size_t max_dp_usage;
+static size_t max_rp_usage;
+
+static void
+run_test_case(test_case *tc)
+{
+ br_x509_minimal_context ctx;
+ br_x509_trust_anchor *anchors;
+ size_t num_anchors;
+ size_t u;
+ const br_hash_class *dnhash;
+ size_t num_certs;
+ blob *certs;
+ br_x509_pkey *ee_pkey_ref;
+ const br_x509_pkey *ee_pkey;
+ unsigned status;
+
+ printf("%s: ", tc->name);
+ fflush(stdout);
+
+ /*
+ * Get the hash function to use for hashing DN. We can use just
+ * any supported hash function, but for the elegance of things,
+ * we will use one of the hash function implementations
+ * supported for this test case (with SHA-1 as fallback).
+ */
+ dnhash = &br_sha1_vtable;
+ for (u = 0; hash_impls[u].id; u ++) {
+ if ((tc->hashes & ((unsigned)1 << (hash_impls[u].id))) != 0) {
+ dnhash = hash_impls[u].impl;
+ }
+ }
+
+ /*
+ * Get trust anchors.
+ */
+ for (num_anchors = 0; tc->ta_names[num_anchors]; num_anchors ++);
+ anchors = xmalloc(num_anchors * sizeof *anchors);
+ for (u = 0; tc->ta_names[u]; u ++) {
+ test_trust_anchor *tta;
+ br_x509_pkey *tak;
+
+ tta = HT_get(trust_anchors, tc->ta_names[u]);
+ if (tta == NULL) {
+ fprintf(stderr, "no such trust anchor: '%s'\n",
+ tc->ta_names[u]);
+ exit(EXIT_FAILURE);
+ }
+ tak = HT_get(keys, tta->key_name);
+ if (tak == NULL) {
+ fprintf(stderr, "no such public key: '%s'\n",
+ tta->key_name);
+ exit(EXIT_FAILURE);
+ }
+ anchors[u].dn = tta->dn;
+ anchors[u].dn_len = tta->dn_len;
+ anchors[u].flags = tta->flags;
+ anchors[u].pkey = *tak;
+ }
+
+ /*
+ * Read all relevant certificates.
+ */
+ for (num_certs = 0; tc->cert_names[num_certs]; num_certs ++);
+ certs = xmalloc(num_certs * sizeof *certs);
+ for (u = 0; u < num_certs; u ++) {
+ certs[u].data = read_file(tc->cert_names[u], &certs[u].len);
+ }
+
+ /*
+ * Get expected EE public key (if any).
+ */
+ if (tc->ee_key_name == NULL) {
+ ee_pkey_ref = NULL;
+ } else {
+ ee_pkey_ref = HT_get(keys, tc->ee_key_name);
+ if (ee_pkey_ref == NULL) {
+ fprintf(stderr, "no such public key: '%s'\n",
+ tc->ee_key_name);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ /*
+ * Initialise the engine.
+ */
+ br_x509_minimal_init(&ctx, dnhash, anchors, num_anchors);
+ for (u = 0; hash_impls[u].id; u ++) {
+ int id;
+
+ id = hash_impls[u].id;
+ if ((tc->hashes & ((unsigned)1 << id)) != 0) {
+ br_x509_minimal_set_hash(&ctx, id, hash_impls[u].impl);
+ }
+ }
+ br_x509_minimal_set_rsa(&ctx, br_rsa_i32_pkcs1_vrfy);
+ br_x509_minimal_set_ecdsa(&ctx,
+ &br_ec_prime_i31, br_ecdsa_i31_vrfy_asn1);
+
+ /*
+ * Set the validation date.
+ */
+ br_x509_minimal_set_time(&ctx, tc->days, tc->seconds);
+
+ /*
+ * Put "canaries" to detect actual stack usage.
+ */
+ for (u = 0; u < (sizeof ctx.dp_stack) / sizeof(uint32_t); u ++) {
+ ctx.dp_stack[u] = 0xA7C083FE;
+ }
+ for (u = 0; u < (sizeof ctx.rp_stack) / sizeof(uint32_t); u ++) {
+ ctx.rp_stack[u] = 0xA7C083FE;
+ }
+
+ /*
+ * Run the engine. We inject certificates by chunks of 100 bytes
+ * in order to exercise the coroutine API.
+ */
+ ctx.vtable->start_chain(&ctx.vtable,
+ tc->key_type_usage, tc->servername);
+ for (u = 0; u < num_certs; u ++) {
+ size_t v;
+
+ ctx.vtable->start_cert(&ctx.vtable, certs[u].len);
+ v = 0;
+ while (v < certs[u].len) {
+ size_t w;
+
+ w = certs[u].len - v;
+ if (w > 100) {
+ w = 100;
+ }
+ ctx.vtable->append(&ctx.vtable, certs[u].data + v, w);
+ v += w;
+ }
+ ctx.vtable->end_cert(&ctx.vtable);
+ }
+ status = ctx.vtable->end_chain(&ctx.vtable);
+ ee_pkey = ctx.vtable->get_pkey(&ctx.vtable);
+
+ /*
+ * Check results. Note that we may still get a public key if
+ * the path is "not trusted" (but otherwise fine).
+ */
+ if (status != tc->status) {
+ fprintf(stderr, "wrong status (got %d, expected %d)\n",
+ status, tc->status);
+ exit(EXIT_FAILURE);
+ }
+ if (status == BR_ERR_X509_NOT_TRUSTED) {
+ ee_pkey = NULL;
+ }
+ if (!eqpkey(ee_pkey, ee_pkey_ref)) {
+ fprintf(stderr, "wrong EE public key\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ * Check stack usage.
+ */
+ for (u = (sizeof ctx.dp_stack) / sizeof(uint32_t); u > 0; u --) {
+ if (ctx.dp_stack[u - 1] != 0xA7C083FE) {
+ if (max_dp_usage < u) {
+ max_dp_usage = u;
+ }
+ break;
+ }
+ }
+ for (u = (sizeof ctx.rp_stack) / sizeof(uint32_t); u > 0; u --) {
+ if (ctx.rp_stack[u - 1] != 0xA7C083FE) {
+ if (max_rp_usage < u) {
+ max_rp_usage = u;
+ }
+ break;
+ }
+ }
+
+ /*
+ * Release everything.
+ */
+ for (u = 0; u < num_certs; u ++) {
+ xfree(certs[u].data);
+ }
+ xfree(certs);
+ xfree(anchors);
+ printf("OK\n");
+}
+
+int
+main(void)
+{
+ size_t u;
+
+ process_conf_file(CONFFILE);
+
+ max_dp_usage = 0;
+ max_rp_usage = 0;
+ for (u = 0; u < all_chains_ptr; u ++) {
+ run_test_case(&all_chains[u]);
+ }
+
+ printf("Maximum data stack usage: %u\n", (unsigned)max_dp_usage);
+ printf("Maximum return stack usage: %u\n", (unsigned)max_rp_usage);
+
+ HT_free(keys, free_key);
+ HT_free(trust_anchors, free_trust_anchor);
+ for (u = 0; u < all_chains_ptr; u ++) {
+ free_test_case_contents(&all_chains[u]);
+ }
+ xfree(all_chains);
+ return 0;
+}
--- /dev/null
+; Most/all of these test chains use the same structure:
+; root -> ica1 -> ica2 -> ee
+; "ica1" is "Intermediate CA 1"
+; "ee" is "end-entity", i.e. the client or server certificate itself
+;
+; In SSL/TLS order, the EE comes first. The root may or may not be included
+; as a self-signed certificate.
+
+[key]
+name = root-rsa2048
+type = RSA
+n = B6D934D450FDB3AF7A73F1CE38BF5D6F45E1FD4EB198C6608326D217D1C5B79AA3C1DE6339979CF05E5CC81C17B988196DF0B62E3050A1546E93C0DBCF30CB9F1E2779F1C3995235AA3DB6DFB0AD7CCB49CDC0EDE766102AE9CE281F2150FA774C2DDAEF3C58EB4EBFCEE9FB1ADAA383A3CDA3CA9380DCDAF317CC7AAB33809CB2D47F463FC53CDC6194B727296E2ABC5B0936D4C63B0DEBBECEDB1D1CBC106A7171B3F2CA289A77F28AEC42EFB14A8EE2F21A322ACDC0A6462C9AC28537917F46A19381A17466DFBAB339209193FA1DA1A885E7E4F907F610F6A82701B67F12C340C3C9E2B0AB49183A64B659B795B59636DF2269AA726A544E2729A30E9715
+e = 010001
+
+[key]
+name = root-p256
+type = EC
+curve = P-256
+q = 047174BAABB9302E81D5E557F9F320680C9CF964DBB4200D6DEA40D04A6E42FDB69A682544F6DF7BC4FCDEDD7BBBC5DB7C763F4166406EDBA787C2E5D8C5F37F8D
+
+[key]
+name = root-p384
+type = EC
+curve = P-384
+q = 040ED28B3F7F0A38A6DB72CB4DAC8198C3D595BFABEE2E4A3CC6797F1A272C57AD715F96B5FDA29C4DD87B75B1438B6A92C4FD0282A3080A857F28AB31FF8B49F805470A01EE551F7F27C914E7E780AE474558D6F5539BAE806626514FE560478B
+
+[key]
+name = root-p521
+type = EC
+curve = P-521
+q = 040168E669615D1B20F2E753D2C86312F51094D3E5C6CF49E8D73418278CD769FE40A84AD4F34865D59D94D5685B389E0CFD0450754CAE81ED1D4A91D0773F7A002ED701DEF2DBDEFC7554E74CD600693DBDE1A7E09CD9044774C744C7CE575BF8B645FF79FCCE06116F61D44FDAE62D3046F4EB41DECB8219B279A5B8CE2A47F3DF0D463B
+
+[key]
+name = ica1-rsa2048
+type = RSA
+n = B3E86BAF9C1652E3810C50AB25CECC0DC7F21F7F50DF2C5C35D6622E632741A7E453A84B27FA1391A3FA094A2F3B5ECF77B38AC1CD49959C750D6474EFE4D74BB9A19B68D2307148EAF74B14DF3F47A9D8BBEC8F28CCFADFB41F947C96FC080528F9E8F42F2FEE629C8A3AE0855860B60F2D30B4C04154914C1F5FADF119F0C022A67DD83F793459427B5BB541C4647F52CF3C3722A12F7925942441C23FFAC775FB48B50D18A7F454F32E6ED84358C4AB50E805AD91B61E0175B3549CDEA09915FBACF15C974951CCEF58126F736BB33414010F5A9DFAAAD693D3E2EAC3ABBC4EEDCC51A1B8F894B6B42CA8862B1FF6514329525E1389B36A78604E4EC01BA5
+e = 010001
+
+[key]
+name = ica2-rsa2048
+type = RSA
+n = AE15F7CBEEE3961BCA63D22681B2D8163423735684FCFDB2E98E9DD0D9D0D706A191EF8D4F604E16BDE6529EE557867B7A7FFCBC34AD86EC9150ADD5C7D18D83E95ABA2FDB0DB92131FAA2FD91EC37836261809C6A82253309DF8F7893EACFDB93B0A2687CEA873E369C4B379A71E52084C3789A2BA42C7E76D561A9131272F14B411BC6A555BA9D8965C06699C0F17C9B61B24E6601B0A9C4FDC8C1D0C789BE2746DE6271BA27F52A850F436026BC2A9D07AAD608DC26D86956A1D308DED858936B0EC2AF783E2574D49F001820BFD7158DB9D13D8900A01264E186C0D580F124B2D2FB4C677CAE3DC9BF47026DE47C0D4490518CCD026237F86FB96701C695
+e = 010001
+
+[key]
+name = ee-rsa2048
+type = RSA
+n = D47A1D27BA2B3A67B2916AFBE78344CAED1C75ADDD4D8362D6AA6895B224217B15AE2A996815ED66F0B858E7D3F52EC6D92A5EE70E2EE7FC6759C0C8617D4BA46FDD9FD9C8858764C7BA1A0F29D496A8789A6B6220A932D0EEA98C286147A2502A63F621DEDAD8D5F07FC5008270E6A3BF5C89274F51927703C3B0CC2E3BEC23F22F5341AF8993FFD280B14397DED619A092127A3D6679E1C1BCE17770A28B3D4684533FE44E424137921E1FFD38B3F7EF873980D356CFF4E013DE64B072A40384C441ED6FFA3EE2CA0420D2D7DC2C822B7AE26DA11C48DBCF894F34973D28A853DAE7C1E17315A330767F8F2342143D5134D25AAD3C9BCBC8FE7F6E8E40F3BD
+e = 010001
+
+[key]
+name = ee-p256
+type = EC
+curve = P-256
+q = 045F389DA7FF4D8AAFF63439461AFC3ADFF423AAA9EAFBC508DE008EBE79A537584C6DDD01CAAB47DF89B6C7171F38FC1D2014DD45C0E08F934E380BFCE999A149
+
+[key]
+name = ee-p384
+type = EC
+curve = P-384
+q = 0415A488877F3D14830E29A1C2F2C0745CE8CF5E684304D1668972389BA615B34E9648D5A7861E49DFFFBFFFEAD7FC6AF11BC4516C3557332DD86DDFDE2A236CCEA844EBD594CCD3ED5B7AE0061BD6595737B59FE754BCDAB6FE38D34D93DBBF30
+
+[key]
+name = ee-p521
+type = EC
+curve = P-521
+q = 040060547ACA9D520FB3272833236CBF8E71AC286A3001FBB1E2C3FD8BAB0817DDE4E4FA53550F120D678F4D55AE4FF36C7C8EAE9E32A08A44FC66F45331E08946077A0139B87FE54B986012A94838C8006034941CD0512E596436D2E8E61CA93585D5C06EAD5094585B5B2A3E013803B3E6AAA1D4156EF09E8352029BB70AC6BF338F918B
+
+; Trust anchor: the root.
+[anchor]
+name = root
+DN_file = dn-root.der
+key = root-rsa2048
+type = CA
+
+; Trust anchor: root with an ECDSA key (in P-256 curve)
+[anchor]
+name = root-p256
+DN_file = dn-root.der
+key = root-p256
+type = CA
+
+; Trust anchor: root with an ECDSA key (in P-384 curve)
+[anchor]
+name = root-p384
+DN_file = dn-root.der
+key = root-p384
+type = CA
+
+; Trust anchor: root with an ECDSA key (in P-521 curve)
+[anchor]
+name = root-p521
+DN_file = dn-root.der
+key = root-p521
+type = CA
+
+; Intermediate CA 1 as trust anchor.
+[anchor]
+name = ica1
+DN_file = dn-ica1.der
+key = ica1-rsa2048
+type = CA
+
+; Intermediate CA 2 as trust anchor.
+[anchor]
+name = ica2
+DN_file = dn-ica2.der
+key = ica2-rsa2048
+type = CA
+
+; EE certificate as trust anchor (direct trust only).
+[anchor]
+name = ee
+DN_file = dn-ee.der
+key = ee-rsa2048
+type = EE
+
+; Base valid chain.
+[chain]
+name = base
+anchors = root
+chain = ee.crt ica2.crt ica1.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; Valid chain except that no trust anchor is provided; this should fail
+; with BR_ERR_X509_NOT_TRUSTED.
+[chain]
+name = noTA
+anchors =
+chain = ee.crt ica2.crt ica1.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+status = 62
+
+; Use of intermediate CA 1 as anchor (extra certificates are ignored).
+[chain]
+name = anchorICA1
+anchors = ica1
+chain = ee.crt ica2.crt junk.crt junk.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; Use of intermediate CA 2 as anchor (extra certificates are ignored).
+[chain]
+name = anchorICA2
+anchors = ica2
+chain = ee.crt junk.crt junk.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; Direct trust of EE.
+[chain]
+name = directTrust
+anchors = ee
+chain = ee.crt junk.crt junk.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; Server name check: name does not match the SAN nor the CN.
+[chain]
+name = wrongName1
+anchors = root
+chain = ee.crt ica2.crt ica1.crt
+servername = foo.example.com
+keytype = RSA
+keyusage = KEYX
+status = 56
+
+; Server name check: name matches the CN but not the SAN, and there is
+; a SAN so the CN is ignored.
+[chain]
+name = wrongName2
+anchors = root
+chain = ee-names.crt ica2.crt ica1.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+status = 56
+
+; Server name check: name does not match CN, but matches the first SAN
+; name.
+[chain]
+name = goodName1
+anchors = root
+chain = ee-names.crt ica2.crt ica1.crt
+servername = foo.example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; Server name check: name does not match CN, but matches the second SAN
+; name.
+[chain]
+name = goodName2
+anchors = root
+chain = ee-names.crt ica2.crt ica1.crt
+servername = barqux.example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; Server name check: no SAN, but the CN matches the server name.
+[chain]
+name = goodName3
+anchors = root
+chain = ee-names2.crt ica2.crt ica1.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; Server name check: no SAN, and the CN does not match the server name.
+[chain]
+name = wrongName3
+anchors = root
+chain = ee-names2.crt ica2.crt ica1.crt
+servername = foo.example.com
+keytype = RSA
+keyusage = KEYX
+status = 56
+
+; Server name check: no SAN, and the CN does not match the server name,
+; although its byte contents seem to match (but with BMPString encoding).
+[chain]
+name = wrongName4
+anchors = root
+chain = ee-names3.crt ica2.crt ica1.crt
+servername = www1.example.com
+keytype = RSA
+keyusage = KEYX
+status = 56
+
+; Server name check: no SAN, and the CN uses BMPString encoding, but we
+; do not actually request a server name check, so this should pass.
+[chain]
+name = ignoreName1
+anchors = root
+chain = ee-names3.crt ica2.crt ica1.crt
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; Wildcard processing: the name 'localhost' should not match because
+; the engine recognises the wildcard only in a '*.' starting sequence,
+; so the lone '*' in a SAN will not be accepted.
+[chain]
+name = wildcard1
+anchors = root
+chain = ee-names4.crt ica2.crt ica1.crt
+servername = localhost
+keytype = RSA
+keyusage = KEYX
+status = 56
+
+; Wildcard processing: the name 'example.com' will be matched by '*.com'.
+[chain]
+name = wildcard2
+anchors = root
+chain = ee-names4.crt ica2.crt ica1.crt
+servername = example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; Wildcard processing: the name 'www.example.com' will be matched by
+; '*.example.com'.
+[chain]
+name = wildcard3
+anchors = root
+chain = ee-names4.crt ica2.crt ica1.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; Wildcard processing: the name 'foo.foo.example.com' will not be matched by
+; 'foo.*.example.com' because we accept the wildcard only in the first name
+; component.
+[chain]
+name = wildcard4
+anchors = root
+chain = ee-names4.crt ica2.crt ica1.crt
+servername = foo.foo.example.com
+keytype = RSA
+keyusage = KEYX
+status = 56
+
+; Wildcard processing: the name 'foo.bar.example.com' will not be matched by
+; 'foo.*.example.com', but '*.bar.example.com' will fit.
+[chain]
+name = wildcard5
+anchors = root
+chain = ee-names4.crt ica2.crt ica1.crt
+servername = foo.bar.example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; Wildcard processing: the name 'foo.bar.example.foobar' will not be matched by
+; '*.*.example.foobar' because we support only a single level of wildcard.
+[chain]
+name = wildcard6
+anchors = root
+chain = ee-names4.crt ica2.crt ica1.crt
+servername = foo.bar.example.foobar
+keytype = RSA
+keyusage = KEYX
+status = 56
+
+; Wildcard processing: the name 'foo.*.example.foobar' will be matched
+; by '*.*.example.foobar' because the '*' in the provided server name matches
+; the second '*' in '*.*.example.foobar'. This is a corner case with no
+; practical impact because expected server names are usually extracted from
+; URL and cannot have embedded '*' in them.
+[chain]
+name = wildcard7
+anchors = root
+chain = ee-names4.crt ica2.crt ica1.crt
+servername = foo.*.example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; Hash function support: the chain uses only SHA-256.
+[chain]
+name = hashSHA256Only
+anchors = root
+chain = ee.crt ica2.crt ica1.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+hashes = sha256
+eekey = ee-rsa2048
+status = 0
+
+; Hash function support: the chain uses only SHA-256.
+[chain]
+name = hashSHA256Unsupported
+anchors = root
+chain = ee.crt ica2.crt ica1.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+hashes = md5 sha1 sha224 sha384 sha512
+status = 49
+
+; Hash function support: signature on EE uses SHA-1.
+[chain]
+name = hashSHA1
+anchors = root
+chain = ee-sha1.crt ica2.crt ica1.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; Hash function support: signature on EE uses SHA-224.
+[chain]
+name = hashSHA224
+anchors = root
+chain = ee-sha224.crt ica2.crt ica1.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; Hash function support: signature on EE uses SHA-384.
+[chain]
+name = hashSHA384
+anchors = root
+chain = ee-sha384.crt ica2.crt ica1.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; Hash function support: signature on EE uses SHA-512.
+[chain]
+name = hashSHA512
+anchors = root
+chain = ee-sha512.crt ica2.crt ica1.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; Hash function support: signature on EE uses MD5. This is rejected by
+; the engine (even though MD5 is supported as a hash function).
+[chain]
+name = hashMD5
+anchors = root
+chain = ee-md5.crt ica2.crt ica1.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+status = 49
+
+; EE certificate has trailing garbage (an extra byte), which should be
+; rejected.
+[chain]
+name = trailingGarbage
+anchors = root
+chain = ee-trailing.crt ica2.crt ica1.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+status = 40
+
+; Signature on EE certificate is incorrect (one byte modified in signature).
+[chain]
+name = badSignature1
+anchors = root
+chain = ee-badsig1.crt ica2.crt ica1.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+status = 52
+
+; Signature on EE certificate is incorrect (one byte modified in serial
+; number).
+[chain]
+name = badSignature2
+anchors = root
+chain = ee-badsig2.crt ica2.crt ica1.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+status = 52
+
+; Signature on EE certificate is incorrect but this is ignored because we
+; use a direct trust model here.
+[chain]
+name = ignoredSignature1
+anchors = ee
+chain = ee-badsig1.crt ica2.crt ica1.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; Signature on EE certificate is incorrect but this is ignored because we
+; use a direct trust model here.
+[chain]
+name = ignoredSignature2
+anchors = ee
+chain = ee-badsig2.crt ica2.crt ica1.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; Intermediate CA 1 has a 1016-bit RSA key, which should be rejected
+; with BR_ERR_X509_WEAK_PUBLIC_KEY.
+[chain]
+name = rsa1016
+anchors = root
+chain = ee.crt ica2-1016.crt ica1-1016.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+status = 60
+
+; Intermediate CA 1 has a 1017-bit RSA key, which should be accepted
+; (because that's 128 bytes, which is the lower limit).
+[chain]
+name = rsa1017
+anchors = root
+chain = ee.crt ica2-1017.crt ica1-1017.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; Intermediate CA 1 has a 4096-bit RSA key, which should be supported.
+[chain]
+name = rsa4096
+anchors = root
+chain = ee.crt ica2-4096.crt ica1-4096.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; EE is valid from 2010/02/17 11:40:35 to 2098/07/20 15:11:08. The
+; start date is in UTCTime, the end date is in GeneralizedTime.
+[chain]
+name = date1
+anchors = ica2
+chain = ee-dates.crt ica2.crt ica1.crt
+time = 2010-02-17 11:40:34Z
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+status = 54
+
+; EE is valid from 2010/02/17 11:40:35 to 2098/07/20 15:11:08. The
+; start date is in UTCTime, the end date is in GeneralizedTime.
+[chain]
+name = date2
+anchors = ica2
+chain = ee-dates.crt ica2.crt ica1.crt
+time = 2010-02-17 11:40:36Z
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; EE is valid from 2010/02/17 11:40:35 to 2098/07/20 15:11:08. The
+; start date is in UTCTime, the end date is in GeneralizedTime.
+[chain]
+name = date3
+anchors = ica2
+chain = ee-dates.crt ica2.crt ica1.crt
+time = 2098-07-20 15:11:07Z
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; EE is valid from 2010/02/17 11:40:35 to 2098/07/20 15:11:08. The
+; start date is in UTCTime, the end date is in GeneralizedTime.
+[chain]
+name = date4
+anchors = ica2
+chain = ee-dates.crt ica2.crt ica1.crt
+time = 2098-07-20 15:11:09Z
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+status = 54
+
+; Intermediate CA 2 certificate is not a CA.
+[chain]
+name = notCA
+anchors = root
+chain = ee-dates.crt ica2-notCA.crt ica1.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+status = 58
+
+; A chain using ECDSA with P-256.
+[chain]
+name = secp256r1
+anchors = root-p256
+chain = ee-p256.crt ica2-p256.crt ica1-p256.crt
+servername = www.example.com
+keytype = EC
+keyusage = SIGN
+eekey = ee-p256
+status = 0
+
+; A chain using ECDSA with P-384.
+[chain]
+name = secp384r1
+anchors = root-p384
+chain = ee-p384.crt ica2-p384.crt ica1-p384.crt
+servername = www.example.com
+keytype = EC
+keyusage = SIGN
+eekey = ee-p384
+status = 0
+
+; A chain using ECDSA with P-521.
+[chain]
+name = secp521r1
+anchors = root-p521
+chain = ee-p521.crt ica2-p521.crt ica1-p521.crt
+servername = www.example.com
+keytype = EC
+keyusage = SIGN
+eekey = ee-p521
+status = 0
+
+; A chain using ECDSA with P-256, signature on EE uses SHA-1.
+[chain]
+name = secp256r1-sha1
+anchors = root-p256
+chain = ee-p256-sha1.crt ica2-p256.crt ica1-p256.crt
+servername = www.example.com
+keytype = EC
+keyusage = SIGN
+eekey = ee-p256
+status = 0
+
+; A chain using ECDSA with P-256, signature on EE uses SHA-224.
+[chain]
+name = secp256r1-sha224
+anchors = root-p256
+chain = ee-p256-sha224.crt ica2-p256.crt ica1-p256.crt
+servername = www.example.com
+keytype = EC
+keyusage = SIGN
+eekey = ee-p256
+status = 0
+
+; A chain using ECDSA with P-256, signature on EE uses SHA-256.
+[chain]
+name = secp256r1-sha256
+anchors = root-p256
+chain = ee-p256-sha256.crt ica2-p256.crt ica1-p256.crt
+servername = www.example.com
+keytype = EC
+keyusage = SIGN
+eekey = ee-p256
+status = 0
+
+; A chain using ECDSA with P-256, signature on EE uses SHA-384.
+[chain]
+name = secp256r1-sha384
+anchors = root-p256
+chain = ee-p256-sha384.crt ica2-p256.crt ica1-p256.crt
+servername = www.example.com
+keytype = EC
+keyusage = SIGN
+eekey = ee-p256
+status = 0
+
+; A chain using ECDSA with P-256, signature on EE uses SHA-512.
+[chain]
+name = secp256r1-sha512
+anchors = root-p256
+chain = ee-p256-sha512.crt ica2-p256.crt ica1-p256.crt
+servername = www.example.com
+keytype = EC
+keyusage = SIGN
+eekey = ee-p256
+status = 0
--- /dev/null
+0'1\v0 \ 6\ 3U\ 4\ 6\13\ 2CA1\180\16\ 6\ 3U\ 4\ 3\13\ fwww.example.com
\ No newline at end of file
--- /dev/null
+011\v0 \ 6\ 3U\ 4\ 6\13\ 2CA1"0 \ 6\ 3U\ 4\ 3\13\19Example Intermediate CA 1
\ No newline at end of file
--- /dev/null
+011\v0 \ 6\ 3U\ 4\ 6\13\ 2CA1"0 \ 6\ 3U\ 4\ 3\13\19Example Intermediate CA 2
\ No newline at end of file
--- /dev/null
+0$1\v0 \ 6\ 3U\ 4\ 6\13\ 2CA1\150\13\ 6\ 3U\ 4\ 3\13\fExample Root
\ No newline at end of file
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include "brssl.h"
+#include "bearssl.h"
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: brssl command [ options ]\n");
+ fprintf(stderr, "available commands:\n");
+ fprintf(stderr, " client run SSL client\n");
+ fprintf(stderr, " server run SSL server\n");
+ fprintf(stderr, " verify verify certificate chain\n");
+ fprintf(stderr, " skey decode private key\n");
+ fprintf(stderr, " ta decode trust anchors\n");
+ fprintf(stderr, " chain make C code for certificate chains\n");
+}
+
+int
+main(int argc, char *argv[])
+{
+ char *cmd;
+
+ if (argc < 2) {
+ usage();
+ return EXIT_FAILURE;
+ }
+ cmd = argv[1];
+ if (eqstr(cmd, "client")) {
+ if (do_client(argc - 2, argv + 2) < 0) {
+ return EXIT_FAILURE;
+ }
+ } else if (eqstr(cmd, "server")) {
+ if (do_server(argc - 2, argv + 2) < 0) {
+ return EXIT_FAILURE;
+ }
+ } else if (eqstr(cmd, "verify")) {
+ if (do_verify(argc - 2, argv + 2) < 0) {
+ return EXIT_FAILURE;
+ }
+ } else if (eqstr(cmd, "skey")) {
+ if (do_skey(argc - 2, argv + 2) < 0) {
+ return EXIT_FAILURE;
+ }
+ } else if (eqstr(cmd, "ta")) {
+ if (do_ta(argc - 2, argv + 2) < 0) {
+ return EXIT_FAILURE;
+ }
+ } else if (eqstr(cmd, "chain")) {
+ if (do_chain(argc - 2, argv + 2) < 0) {
+ return EXIT_FAILURE;
+ }
+ } else {
+ fprintf(stderr, "unknown command: '%s'\n", cmd);
+ usage();
+ return EXIT_FAILURE;
+ }
+ return 0;
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+#ifndef BRSSL_H__
+#define BRSSL_H__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "bearssl.h"
+
+/*
+ * malloc() wrapper:
+ * -- If len is 0, then NULL is returned.
+ * -- If len is non-zero, and allocation fails, then an error message is
+ * printed and the process exits with an error code.
+ */
+void *xmalloc(size_t len);
+
+/*
+ * free() wrapper, meant to release blocks allocated with xmalloc().
+ */
+void xfree(void *buf);
+
+/*
+ * Duplicate a character string into a newly allocated block.
+ */
+char *xstrdup(const void *src);
+
+/*
+ * Allocate a new block with the provided length, filled with a copy
+ * of exactly that many bytes starting at address 'src'.
+ */
+void *xblobdup(const void *src, size_t len);
+
+/*
+ * Duplicate a public key, into newly allocated blocks. The returned
+ * key must be later on released with xfreepkey().
+ */
+br_x509_pkey *xpkeydup(const br_x509_pkey *pk);
+
+/*
+ * Release a public key that was allocated with xpkeydup(). If pk is NULL,
+ * this function does nothing.
+ */
+void xfreepkey(br_x509_pkey *pk);
+
+/*
+ * Macros for growable arrays.
+ */
+
+/*
+ * Make a structure type for a vector of 'type'.
+ */
+#define VECTOR(type) struct { \
+ type *buf; \
+ size_t ptr, len; \
+ }
+
+/*
+ * Constant initialiser for a vector.
+ */
+#define VEC_INIT { 0, 0, 0 }
+
+/*
+ * Clear a vector.
+ */
+#define VEC_CLEAR(vec) do { \
+ xfree((vec).buf); \
+ (vec).buf = NULL; \
+ (vec).ptr = 0; \
+ (vec).len = 0; \
+ } while (0)
+
+/*
+ * Clear a vector, first calling the provided function on each vector
+ * element.
+ */
+#define VEC_CLEAREXT(vec, fun) do { \
+ size_t vec_tmp; \
+ for (vec_tmp = 0; vec_tmp < (vec).ptr; vec_tmp ++) { \
+ (fun)(&(vec).buf[vec_tmp]); \
+ } \
+ VEC_CLEAR(vec); \
+ } while (0)
+
+/*
+ * Add a value at the end of a vector.
+ */
+#define VEC_ADD(vec, x) do { \
+ (vec).buf = vector_expand((vec).buf, sizeof *((vec).buf), \
+ &(vec).ptr, &(vec).len, 1); \
+ (vec).buf[(vec).ptr ++] = (x); \
+ } while (0)
+
+/*
+ * Add several values at the end of a vector.
+ */
+#define VEC_ADDMANY(vec, xp, num) do { \
+ size_t vec_num = (num); \
+ (vec).buf = vector_expand((vec).buf, sizeof *((vec).buf), \
+ &(vec).ptr, &(vec).len, vec_num); \
+ memcpy((vec).buf + (vec).ptr, \
+ (xp), vec_num * sizeof *((vec).buf)); \
+ (vec).ptr += vec_num; \
+ } while (0)
+
+/*
+ * Access a vector element by index. This is a lvalue, and can be modified.
+ */
+#define VEC_ELT(vec, idx) ((vec).buf[idx])
+
+/*
+ * Get current vector length.
+ */
+#define VEC_LEN(vec) ((vec).ptr)
+
+/*
+ * Copy all vector elements into a newly allocated block.
+ */
+#define VEC_TOARRAY(vec) xblobdup((vec).buf, sizeof *((vec).buf) * (vec).ptr)
+
+/*
+ * Internal function used to handle memory allocations for vectors.
+ */
+void *vector_expand(void *buf,
+ size_t esize, size_t *ptr, size_t *len, size_t extra);
+
+/*
+ * Type for a vector of bytes.
+ */
+typedef VECTOR(unsigned char) bvector;
+
+/*
+ * Compare two strings for equality; returned value is 1 if the strings
+ * are to be considered equal, 0 otherwise. Comparison is case-insensitive
+ * (ASCII letters only) and skips some characters (all whitespace, defined
+ * as ASCII codes 0 to 32 inclusive, and also '-', '_', '.', '/', '+' and
+ * ':').
+ */
+int eqstr(const char *s1, const char *s2);
+
+/*
+ * Structure for a known protocol version.
+ */
+typedef struct {
+ const char *name;
+ unsigned version;
+ const char *comment;
+} protocol_version;
+
+/*
+ * Known protocol versions. Last element has a NULL name.
+ */
+extern const protocol_version protocol_versions[];
+
+/*
+ * Parse a version name. If the name is not recognized, then an error
+ * message is printed, and 0 is returned.
+ */
+unsigned parse_version(const char *name, size_t len);
+
+/*
+ * Type for a known hash function.
+ */
+typedef struct {
+ const char *name;
+ const br_hash_class *hclass;
+ const char *comment;
+} hash_function;
+
+/*
+ * Known hash functions. Last element has a NULL name.
+ */
+extern const hash_function hash_functions[];
+
+/*
+ * Parse hash function names. This function expects a comma-separated
+ * list of names, and returns a bit mask corresponding to the matched
+ * names. If one of the name does not match, or the list is empty, then
+ * an error message is printed, and 0 is returned.
+ */
+unsigned parse_hash_functions(const char *arg);
+
+/*
+ * Type for a known cipher suite.
+ */
+typedef struct {
+ const char *name;
+ uint16_t suite;
+ unsigned req;
+ const char *comment;
+} cipher_suite;
+
+/*
+ * Known cipher suites. Last element has a NULL name.
+ */
+extern const cipher_suite cipher_suites[];
+
+/*
+ * Flags for cipher suite requirements.
+ */
+#define REQ_TLS12 0x0001 /* suite needs TLS 1.2 */
+#define REQ_SHA1 0x0002 /* suite needs SHA-1 */
+#define REQ_SHA256 0x0004 /* suite needs SHA-256 */
+#define REQ_SHA384 0x0008 /* suite needs SHA-384 */
+#define REQ_AESCBC 0x0010 /* suite needs AES/CBC encryption */
+#define REQ_AESGCM 0x0020 /* suite needs AES/GCM encryption */
+#define REQ_3DESCBC 0x0040 /* suite needs 3DES/CBC encryption */
+#define REQ_RSAKEYX 0x0080 /* suite uses RSA key exchange */
+#define REQ_ECDHE_RSA 0x0100 /* suite uses ECDHE_RSA key exchange */
+#define REQ_ECDHE_ECDSA 0x0200 /* suite uses ECDHE_ECDSA key exchange */
+#define REQ_ECDH 0x0400 /* suite uses static ECDH key exchange */
+
+/*
+ * Parse a list of cipher suite names. The names are comma-separated. If
+ * one of the name is not recognised, or the list is empty, then an
+ * appropriate error message is printed, and NULL is returned.
+ * The returned array is allocated with xmalloc() and must be released
+ * by the caller. That array is terminated with a dummy entry whose 'name'
+ * field is NULL. The number of entries (not counting the dummy entry)
+ * is also written into '*num'.
+ */
+cipher_suite *parse_suites(const char *arg, size_t *num);
+
+/*
+ * Get the name of a cipher suite. Returned value is NULL if the suite is
+ * not recognized.
+ */
+const char *get_suite_name(unsigned suite);
+
+/*
+ * Get the name of a cipher suite. The name is written in the provided
+ * buffer; if the suite is not recognised, then the name is
+ * "unknown (0x****)" where "****" is the hexadecimal value of the suite.
+ * If the name does not fit in the provided buffer, then dst[0] is set
+ * to 0 (unless len is 0, in which case nothing is written), and -1 is
+ * returned. Otherwise, the name is written in dst[] (with a terminating
+ * 0), and this function returns 0.
+ */
+int get_suite_name_ext(unsigned suite, char *dst, size_t len);
+
+/*
+ * Print out all known names (for protocol versions, cipher suites...).
+ */
+void list_names(void);
+
+/*
+ * Get the symbolic name for an elliptic curve (by ID).
+ */
+const char *ec_curve_name(int curve);
+
+/*
+ * Read a file completely. The returned block is allocated with xmalloc()
+ * and must be released by the caller.
+ * If the file cannot be found or read completely, or is empty, then an
+ * appropriate error message is written, and NULL is returned.
+ */
+unsigned char *read_file(const char *fname, size_t *len);
+
+/*
+ * Write a file completely. This returns 0 on success, -1 on error. On
+ * error, an appropriate error message is printed.
+ */
+int write_file(const char *fname, const void *data, size_t len);
+
+/*
+ * This function returns non-zero if the provided buffer "looks like"
+ * a DER-encoded ASN.1 object (criteria: it has the tag for a SEQUENCE
+ * with a definite length that matches the total object length).
+ */
+int looks_like_DER(const unsigned char *buf, size_t len);
+
+/*
+ * Type for a named blob (the 'name' is a normalised PEM header name).
+ */
+typedef struct {
+ char *name;
+ unsigned char *data;
+ size_t data_len;
+} pem_object;
+
+/*
+ * Release the contents of a named blob (buffer and name).
+ */
+void free_pem_object_contents(pem_object *po);
+
+/*
+ * Decode a buffer as a PEM file, and return all objects. On error, NULL
+ * is returned and an error message is printed. Absence of any object
+ * is an error.
+ *
+ * The returned array is terminated by a dummy object whose 'name' is
+ * NULL. The number of objects (not counting the dummy terminator) is
+ * written in '*num'.
+ */
+pem_object *decode_pem(const void *src, size_t len, size_t *num);
+
+/*
+ * Get the certificate(s) from a file. This accepts both a single
+ * DER-encoded certificate, and a text file that contains
+ * PEM-encoded certificates (and possibly other objects, which are
+ * then ignored).
+ *
+ * On decoding error, or if the file turns out to contain no certificate
+ * at all, then an error message is printed and NULL is returned.
+ *
+ * The returned array, and all referenced buffers, are allocated with
+ * xmalloc() and must be released by the caller. The returned array
+ * ends with a dummy entry whose 'data' field is NULL.
+ * The number of decoded certificates (not counting the dummy entry)
+ * is written into '*num'.
+ */
+br_x509_certificate *read_certificates(const char *fname, size_t *num);
+
+/*
+ * Interpret a certificate as a trust anchor. The trust anchor is
+ * newly allocated with xmalloc() and the caller must release it.
+ * On decoding error, an error message is printed, and this function
+ * returns NULL.
+ */
+br_x509_trust_anchor *certificate_to_trust_anchor(br_x509_certificate *xc);
+
+/*
+ * Type for a vector of trust anchors.
+ */
+typedef VECTOR(br_x509_trust_anchor) anchor_list;
+
+/*
+ * Release contents for a trust anchor (assuming they were dynamically
+ * allocated with xmalloc()). The structure itself is NOT released.
+ */
+void free_ta_contents(br_x509_trust_anchor *ta);
+
+/*
+ * Decode certificates from a file and interpret them as trust anchors.
+ * The trust anchors are added to the provided list. The number of found
+ * anchors is returned; on error, 0 is returned (finding no anchor at
+ * all is considered an error). An appropriate error message is displayed.
+ */
+size_t read_trust_anchors(anchor_list *dst, const char *fname);
+
+/*
+ * Special "no anchor" X.509 validator that wraps around another X.509
+ * validator and turns "not trusted" error codes into success. This is
+ * by definition insecure, but convenient for debug purposes.
+ */
+typedef struct {
+ const br_x509_class *vtable;
+ const br_x509_class **inner;
+} x509_noanchor_context;
+extern const br_x509_class x509_noanchor_vtable;
+
+/*
+ * Initialise a "no anchor" X.509 validator.
+ */
+void x509_noanchor_init(x509_noanchor_context *xwc,
+ const br_x509_class **inner);
+
+/*
+ * Aggregate type for a private key.
+ */
+typedef struct {
+ int key_type; /* BR_KEYTYPE_RSA or BR_KEYTYPE_EC */
+ union {
+ br_rsa_private_key rsa;
+ br_ec_private_key ec;
+ } key;
+} private_key;
+
+/*
+ * Decode a private key from a file. On error, this prints an error
+ * message and returns NULL.
+ */
+private_key *read_private_key(const char *fname);
+
+/*
+ * Free a private key.
+ */
+void free_private_key(private_key *sk);
+
+/*
+ * Find the symbolic name and the description for an error. If 'err' is
+ * recognised then the error symbolic name is returned; if 'comment' is
+ * not NULL then '*comment' is then set to a descriptive human-readable
+ * message. If the error code 'err' is not recognised, then '*comment' is
+ * untouched and this function returns NULL.
+ */
+const char *find_error_name(int err, const char **comment);
+
+/*
+ * Run a SSL engine, with a socket connected to the peer, and using
+ * stdin/stdout to exchange application data.
+ *
+ * Returned value:
+ * 0 SSL connection closed successfully
+ * x > 0 SSL error "x"
+ * -1 early socket close
+ * -2 stdout was closed, or something failed badly
+ */
+int run_ssl_engine(br_ssl_engine_context *eng, int fd, unsigned flags);
+
+#define RUN_ENGINE_VERBOSE 0x0001 /* enable verbose messages */
+#define RUN_ENGINE_TRACE 0x0002 /* hex dump of records */
+
+/*
+ * Do the "client" command. Returned value is 0 on success, -1 on failure.
+ * Command-line arguments start _after_ the command name.
+ */
+int do_client(int argc, char *argv[]);
+
+/*
+ * Do the "server" command. Returned value is 0 on success, -1 on failure.
+ * Command-line arguments start _after_ the command name.
+ */
+int do_server(int argc, char *argv[]);
+
+/*
+ * Do the "verify" command. Returned value is 0 on success, -1 on failure.
+ * Command-line arguments start _after_ the command name.
+ */
+int do_verify(int argc, char *argv[]);
+
+/*
+ * Do the "skey" command. Returned value is 0 on success, -1 on failure.
+ * Command-line arguments start _after_ the command name.
+ */
+int do_skey(int argc, char *argv[]);
+
+/*
+ * Do the "ta" command. Returned value is 0 on success, -1 on failure.
+ * Command-line arguments start _after_ the command name.
+ */
+int do_ta(int argc, char *argv[]);
+
+/*
+ * Do the "chain" command. Returned value is 0 on success, -1 on failure.
+ * Command-line arguments start _after_ the command name.
+ */
+int do_chain(int argc, char *argv[]);
+
+#endif
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include "brssl.h"
+
+static void
+dn_append(void *ctx, const void *buf, size_t len)
+{
+ VEC_ADDMANY(*(bvector *)ctx, buf, len);
+}
+
+static int
+certificate_to_trust_anchor_inner(br_x509_trust_anchor *ta,
+ br_x509_certificate *xc)
+{
+ br_x509_decoder_context dc;
+ bvector vdn = VEC_INIT;
+ br_x509_pkey *pk;
+
+ br_x509_decoder_init(&dc, dn_append, &vdn);
+ br_x509_decoder_push(&dc, xc->data, xc->data_len);
+ pk = br_x509_decoder_get_pkey(&dc);
+ if (pk == NULL) {
+ fprintf(stderr, "ERROR: CA decoding failed with error %d\n",
+ br_x509_decoder_last_error(&dc));
+ VEC_CLEAR(vdn);
+ return -1;
+ }
+ ta->dn = VEC_TOARRAY(vdn);
+ ta->dn_len = VEC_LEN(vdn);
+ VEC_CLEAR(vdn);
+ ta->flags = 0;
+ if (br_x509_decoder_isCA(&dc)) {
+ ta->flags |= BR_X509_TA_CA;
+ }
+ switch (pk->key_type) {
+ case BR_KEYTYPE_RSA:
+ ta->pkey.key_type = BR_KEYTYPE_RSA;
+ ta->pkey.key.rsa.n = xblobdup(pk->key.rsa.n, pk->key.rsa.nlen);
+ ta->pkey.key.rsa.nlen = pk->key.rsa.nlen;
+ ta->pkey.key.rsa.e = xblobdup(pk->key.rsa.e, pk->key.rsa.elen);
+ ta->pkey.key.rsa.elen = pk->key.rsa.elen;
+ break;
+ case BR_KEYTYPE_EC:
+ ta->pkey.key_type = BR_KEYTYPE_EC;
+ ta->pkey.key.ec.curve = pk->key.ec.curve;
+ ta->pkey.key.ec.q = xblobdup(pk->key.ec.q, pk->key.ec.qlen);
+ ta->pkey.key.ec.qlen = pk->key.ec.qlen;
+ break;
+ default:
+ fprintf(stderr, "ERROR: unsupported public key type in CA\n");
+ xfree(ta->dn);
+ return -1;
+ }
+ return 0;
+}
+
+/* see brssl.h */
+br_x509_trust_anchor *
+certificate_to_trust_anchor(br_x509_certificate *xc)
+{
+ br_x509_trust_anchor ta;
+
+ if (certificate_to_trust_anchor_inner(&ta, xc) < 0) {
+ return NULL;
+ } else {
+ return xblobdup(&ta, sizeof ta);
+ }
+}
+
+/* see brssl.h */
+void
+free_ta_contents(br_x509_trust_anchor *ta)
+{
+ xfree(ta->dn);
+ switch (ta->pkey.key_type) {
+ case BR_KEYTYPE_RSA:
+ xfree(ta->pkey.key.rsa.n);
+ xfree(ta->pkey.key.rsa.e);
+ break;
+ case BR_KEYTYPE_EC:
+ xfree(ta->pkey.key.ec.q);
+ break;
+ }
+}
+
+/* see brssl.h */
+size_t
+read_trust_anchors(anchor_list *dst, const char *fname)
+{
+ br_x509_certificate *xcs;
+ anchor_list tas = VEC_INIT;
+ size_t u, num;
+
+ xcs = read_certificates(fname, &num);
+ if (xcs == NULL) {
+ return 0;
+ }
+ for (u = 0; u < num; u ++) {
+ br_x509_trust_anchor ta;
+
+ if (certificate_to_trust_anchor_inner(&ta, &xcs[u]) < 0) {
+ VEC_CLEAREXT(tas, free_ta_contents);
+ return 0;
+ }
+ VEC_ADD(tas, ta);
+ }
+ VEC_ADDMANY(*dst, &VEC_ELT(tas, 0), num);
+ VEC_CLEAR(tas);
+ return num;
+}
+
+static void
+xwc_start_chain(const br_x509_class **ctx,
+ unsigned expected_key_type, const char *server_name)
+{
+ x509_noanchor_context *xwc;
+
+ xwc = (x509_noanchor_context *)ctx;
+ (*xwc->inner)->start_chain(xwc->inner,
+ expected_key_type, server_name);
+}
+
+static void
+xwc_start_cert(const br_x509_class **ctx, uint32_t length)
+{
+ x509_noanchor_context *xwc;
+
+ xwc = (x509_noanchor_context *)ctx;
+ (*xwc->inner)->start_cert(xwc->inner, length);
+}
+
+static void
+xwc_append(const br_x509_class **ctx, const unsigned char *buf, size_t len)
+{
+ x509_noanchor_context *xwc;
+
+ xwc = (x509_noanchor_context *)ctx;
+ (*xwc->inner)->append(xwc->inner, buf, len);
+}
+
+static void
+xwc_end_cert(const br_x509_class **ctx)
+{
+ x509_noanchor_context *xwc;
+
+ xwc = (x509_noanchor_context *)ctx;
+ (*xwc->inner)->end_cert(xwc->inner);
+}
+
+static unsigned
+xwc_end_chain(const br_x509_class **ctx)
+{
+ x509_noanchor_context *xwc;
+ unsigned r;
+
+ xwc = (x509_noanchor_context *)ctx;
+ r = (*xwc->inner)->end_chain(xwc->inner);
+ if (r == BR_ERR_X509_NOT_TRUSTED) {
+ r = 0;
+ }
+ return r;
+}
+
+static const br_x509_pkey *
+xwc_get_pkey(const br_x509_class *const *ctx)
+{
+ x509_noanchor_context *xwc;
+
+ xwc = (x509_noanchor_context *)ctx;
+ return (*xwc->inner)->get_pkey(xwc->inner);
+}
+
+/* see brssl.h */
+const br_x509_class x509_noanchor_vtable = {
+ sizeof(x509_noanchor_context),
+ xwc_start_chain,
+ xwc_start_cert,
+ xwc_append,
+ xwc_end_cert,
+ xwc_end_chain,
+ xwc_get_pkey
+};
+
+/* see brssl.h */
+void
+x509_noanchor_init(x509_noanchor_context *xwc, const br_x509_class **inner)
+{
+ xwc->vtable = &x509_noanchor_vtable;
+ xwc->inner = inner;
+}
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include "brssl.h"
+#include "bearssl.h"
+
+static void
+print_blob(const char *name, const unsigned char *buf, size_t len)
+{
+ size_t u;
+
+ printf("\nstatic const unsigned char %s[] = {", name);
+ for (u = 0; u < len; u ++) {
+ if (u != 0) {
+ printf(",");
+ }
+ if (u % 12 == 0) {
+ printf("\n\t");
+ } else {
+ printf(" ");
+ }
+ printf("0x%02X", buf[u]);
+ }
+ printf("\n};\n");
+}
+
+static void
+usage_chain(void)
+{
+ fprintf(stderr,
+"usage: brssl chain [ options ] file...\n");
+ fprintf(stderr,
+"options:\n");
+ fprintf(stderr,
+" -q suppress verbose messages\n");
+}
+
+/* see brssl.h */
+int
+do_chain(int argc, char *argv[])
+{
+ int retcode;
+ int verbose;
+ int i, num_files;
+ long k, ctr;
+
+ retcode = 0;
+ verbose = 1;
+ num_files = 0;
+ for (i = 0; i < argc; i ++) {
+ const char *arg;
+
+ arg = argv[i];
+ if (arg[0] != '-') {
+ num_files ++;
+ continue;
+ }
+ argv[i] = NULL;
+ if (eqstr(arg, "-v") || eqstr(arg, "-verbose")) {
+ verbose = 1;
+ } else if (eqstr(arg, "-q") || eqstr(arg, "-quiet")) {
+ verbose = 0;
+ } else {
+ fprintf(stderr, "ERROR: unknown option: '%s'\n", arg);
+ usage_chain();
+ goto chain_exit_error;
+ }
+ }
+ if (num_files == 0) {
+ fprintf(stderr, "ERROR: no certificate file provided\n");
+ usage_chain();
+ goto chain_exit_error;
+ }
+
+ ctr = 0;
+ for (i = 0; i < argc; i ++) {
+ const char *fname;
+ br_x509_certificate *xcs;
+ size_t u, num;
+
+ fname = argv[i];
+ if (fname == NULL) {
+ continue;
+ }
+ if (verbose) {
+ fprintf(stderr, "Reading file '%s': ", fname);
+ fflush(stderr);
+ }
+ xcs = read_certificates(fname, &num);
+ if (xcs == NULL) {
+ goto chain_exit_error;
+ }
+ if (verbose) {
+ fprintf(stderr, "%lu certificate%s\n",
+ (unsigned long)num, num > 1 ? "s" : "");
+ }
+ for (u = 0; u < num; u ++) {
+ char tmp[50];
+
+ sprintf(tmp, "CERT%ld", ctr ++);
+ print_blob(tmp, xcs[u].data, xcs[u].data_len);
+ xfree(xcs[u].data);
+ }
+ xfree(xcs);
+ }
+
+ printf("\nstatic const br_x509_certificate CHAIN[] = {");
+ for (k = 0; k < ctr; k ++) {
+ if (k != 0) {
+ printf(",");
+ }
+ printf("\n\t{ (unsigned char *)CERT%ld, sizeof CERT%ld }",
+ k, k);
+ }
+ printf("\n};\n");
+ printf("\n#define CHAIN_LEN %ld\n", ctr);
+
+ /*
+ * Release allocated structures.
+ */
+chain_exit:
+ return retcode;
+
+chain_exit_error:
+ retcode = -1;
+ goto chain_exit;
+}
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/poll.h>
+
+#include "brssl.h"
+#include "bearssl.h"
+
+static int
+host_connect(const char *host, const char *port, int verbose)
+{
+ struct addrinfo hints, *si, *p;
+ int fd;
+ int err;
+
+ memset(&hints, 0, sizeof hints);
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ err = getaddrinfo(host, port, &hints, &si);
+ if (err != 0) {
+ fprintf(stderr, "ERROR: getaddrinfo(): %s\n",
+ gai_strerror(err));
+ return -1;
+ }
+ fd = -1;
+ for (p = si; p != NULL; p = p->ai_next) {
+ struct sockaddr *sa;
+ void *addr;
+ char tmp[INET6_ADDRSTRLEN + 50];
+
+ sa = (struct sockaddr *)p->ai_addr;
+ if (sa->sa_family == AF_INET) {
+ addr = &((struct sockaddr_in *)sa)->sin_addr;
+ } else if (sa->sa_family == AF_INET6) {
+ addr = &((struct sockaddr_in6 *)sa)->sin6_addr;
+ } else {
+ addr = NULL;
+ }
+ if (addr != NULL) {
+ inet_ntop(p->ai_family, addr, tmp, sizeof tmp);
+ } else {
+ sprintf(tmp, "<unknown family: %d>",
+ (int)sa->sa_family);
+ }
+ if (verbose) {
+ fprintf(stderr, "connecting to: %s\n", tmp);
+ }
+ fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
+ if (fd < 0) {
+ if (verbose) {
+ perror("socket()");
+ }
+ continue;
+ }
+ if (connect(fd, p->ai_addr, p->ai_addrlen) < 0) {
+ if (verbose) {
+ perror("connect()");
+ }
+ close(fd);
+ continue;
+ }
+ break;
+ }
+ if (p == NULL) {
+ freeaddrinfo(si);
+ fprintf(stderr, "ERROR: failed to connect\n");
+ return -1;
+ }
+ freeaddrinfo(si);
+ if (verbose) {
+ fprintf(stderr, "connected.\n");
+ }
+
+ /*
+ * We make the socket non-blocking, since we are going to use
+ * poll() to organise I/O.
+ */
+ fcntl(fd, F_SETFL, O_NONBLOCK);
+ return fd;
+}
+
+static void
+usage_client(void)
+{
+ fprintf(stderr,
+"usage: brssl client server[:port] [ options ]\n");
+ fprintf(stderr,
+"options:\n");
+ fprintf(stderr,
+" -q suppress verbose messages\n");
+ fprintf(stderr,
+" -trace activate extra debug messages (dump of all packets)\n");
+ fprintf(stderr,
+" -sni name use this specific name for SNI\n");
+ fprintf(stderr,
+" -nosni do not send any SNI\n");
+ fprintf(stderr,
+" -mono use monodirectional buffering\n");
+ fprintf(stderr,
+" -buf length set the I/O buffer length (in bytes)\n");
+ fprintf(stderr,
+" -CA file add certificates in 'file' to trust anchors\n");
+ fprintf(stderr,
+" -list list supported names (protocols, algorithms...)\n");
+ fprintf(stderr,
+" -vmin name set minimum supported version (default: TLS-1.0)\n");
+ fprintf(stderr,
+" -vmax name set maximum supported version (default: TLS-1.2)\n");
+ fprintf(stderr,
+" -cs names set list of supported cipher suites (comma-separated)\n");
+ fprintf(stderr,
+" -hf names add support for some hash functions (comma-separated)\n");
+}
+
+/* see brssl.h */
+int
+do_client(int argc, char *argv[])
+{
+ int retcode;
+ int verbose;
+ int trace;
+ int i, bidi;
+ const char *server_name;
+ char *host;
+ char *port;
+ const char *sni;
+ anchor_list anchors = VEC_INIT;
+ unsigned vmin, vmax;
+ cipher_suite *suites;
+ size_t num_suites;
+ uint16_t *suite_ids;
+ unsigned hfuns;
+ size_t u;
+ br_ssl_client_context cc;
+ br_x509_minimal_context xc;
+ x509_noanchor_context xwc;
+ const br_hash_class *dnhash;
+ unsigned char *iobuf;
+ size_t iobuf_len;
+ int fd;
+
+ retcode = 0;
+ verbose = 1;
+ trace = 0;
+ server_name = NULL;
+ host = NULL;
+ port = NULL;
+ sni = NULL;
+ bidi = 1;
+ vmin = 0;
+ vmax = 0;
+ suites = NULL;
+ num_suites = 0;
+ hfuns = 0;
+ suite_ids = NULL;
+ iobuf = NULL;
+ iobuf_len = 0;
+ fd = -1;
+ for (i = 0; i < argc; i ++) {
+ const char *arg;
+
+ arg = argv[i];
+ if (arg[0] != '-') {
+ if (server_name != NULL) {
+ fprintf(stderr,
+ "ERROR: duplicate server name\n");
+ usage_client();
+ goto client_exit_error;
+ }
+ server_name = arg;
+ continue;
+ }
+ if (eqstr(arg, "-v") || eqstr(arg, "-verbose")) {
+ verbose = 1;
+ } else if (eqstr(arg, "-q") || eqstr(arg, "-quiet")) {
+ verbose = 0;
+ } else if (eqstr(arg, "-trace")) {
+ trace = 1;
+ } else if (eqstr(arg, "-sni")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-sni'\n");
+ usage_client();
+ goto client_exit_error;
+ }
+ if (sni != NULL) {
+ fprintf(stderr, "ERROR: duplicate SNI\n");
+ usage_client();
+ goto client_exit_error;
+ }
+ sni = argv[i];
+ } else if (eqstr(arg, "-nosni")) {
+ if (sni != NULL) {
+ fprintf(stderr, "ERROR: duplicate SNI\n");
+ usage_client();
+ goto client_exit_error;
+ }
+ sni = "";
+ } else if (eqstr(arg, "-mono")) {
+ bidi = 0;
+ } else if (eqstr(arg, "-buf")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-buf'\n");
+ usage_client();
+ goto client_exit_error;
+ }
+ arg = argv[i];
+ if (iobuf_len != 0) {
+ fprintf(stderr,
+ "ERROR: duplicate I/O buffer length\n");
+ usage_client();
+ goto client_exit_error;
+ }
+ iobuf_len = strtoul(arg, 0, 10);
+ } else if (eqstr(arg, "-CA")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-CA'\n");
+ usage_client();
+ goto client_exit_error;
+ }
+ arg = argv[i];
+ if (read_trust_anchors(&anchors, arg) == 0) {
+ usage_client();
+ goto client_exit_error;
+ }
+ } else if (eqstr(arg, "-list")) {
+ list_names();
+ goto client_exit;
+ } else if (eqstr(arg, "-vmin")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-vmin'\n");
+ usage_client();
+ goto client_exit_error;
+ }
+ arg = argv[i];
+ if (vmin != 0) {
+ fprintf(stderr,
+ "ERROR: duplicate minimum version\n");
+ usage_client();
+ goto client_exit_error;
+ }
+ vmin = parse_version(arg, strlen(arg));
+ if (vmin == 0) {
+ fprintf(stderr,
+ "ERROR: unrecognised version '%s'\n",
+ arg);
+ usage_client();
+ goto client_exit_error;
+ }
+ } else if (eqstr(arg, "-vmax")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-vmax'\n");
+ usage_client();
+ goto client_exit_error;
+ }
+ arg = argv[i];
+ if (vmax != 0) {
+ fprintf(stderr,
+ "ERROR: duplicate maximum version\n");
+ usage_client();
+ goto client_exit_error;
+ }
+ vmax = parse_version(arg, strlen(arg));
+ if (vmax == 0) {
+ fprintf(stderr,
+ "ERROR: unrecognised version '%s'\n",
+ arg);
+ usage_client();
+ goto client_exit_error;
+ }
+ } else if (eqstr(arg, "-cs")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-cs'\n");
+ usage_client();
+ goto client_exit_error;
+ }
+ arg = argv[i];
+ if (suites != NULL) {
+ fprintf(stderr, "ERROR: duplicate list"
+ " of cipher suites\n");
+ usage_client();
+ goto client_exit_error;
+ }
+ suites = parse_suites(arg, &num_suites);
+ if (suites == NULL) {
+ usage_client();
+ goto client_exit_error;
+ }
+ } else if (eqstr(arg, "-hf")) {
+ unsigned x;
+
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-hf'\n");
+ usage_client();
+ goto client_exit_error;
+ }
+ arg = argv[i];
+ x = parse_hash_functions(arg);
+ if (x == 0) {
+ usage_client();
+ goto client_exit_error;
+ }
+ hfuns |= x;
+ } else {
+ fprintf(stderr, "ERROR: unknown option: '%s'\n", arg);
+ usage_client();
+ goto client_exit_error;
+ }
+ }
+ if (server_name == NULL) {
+ fprintf(stderr, "ERROR: no server name/address provided\n");
+ usage_client();
+ goto client_exit_error;
+ }
+ for (u = strlen(server_name); u > 0; u --) {
+ int c = server_name[u - 1];
+ if (c == ':') {
+ break;
+ }
+ if (c < '0' || c > '9') {
+ u = 0;
+ break;
+ }
+ }
+ if (u == 0) {
+ host = xstrdup(server_name);
+ port = "443";
+ } else {
+ port = xstrdup(server_name + u);
+ host = xmalloc(u);
+ memcpy(host, server_name, u - 1);
+ host[u - 1] = 0;
+ }
+ if (sni == NULL) {
+ sni = host;
+ }
+
+ if (vmin == 0) {
+ vmin = BR_TLS10;
+ }
+ if (vmax == 0) {
+ vmax = BR_TLS12;
+ }
+ if (vmax < vmin) {
+ fprintf(stderr, "ERROR: impossible minimum/maximum protocol"
+ " version combination\n");
+ usage_client();
+ goto client_exit_error;
+ }
+ if (suites == NULL) {
+ num_suites = 0;
+
+ for (u = 0; cipher_suites[u].name; u ++) {
+ if ((cipher_suites[u].req & REQ_TLS12) == 0
+ || vmax >= BR_TLS12)
+ {
+ num_suites ++;
+ }
+ }
+ suites = xmalloc(num_suites * sizeof *suites);
+ num_suites = 0;
+ for (u = 0; cipher_suites[u].name; u ++) {
+ if ((cipher_suites[u].req & REQ_TLS12) == 0
+ || vmax >= BR_TLS12)
+ {
+ suites[num_suites ++] = cipher_suites[u];
+ }
+ }
+ }
+ if (hfuns == 0) {
+ hfuns = (unsigned)-1;
+ }
+ if (iobuf_len == 0) {
+ if (bidi) {
+ iobuf_len = BR_SSL_BUFSIZE_BIDI;
+ } else {
+ iobuf_len = BR_SSL_BUFSIZE_MONO;
+ }
+ }
+ iobuf = xmalloc(iobuf_len);
+
+ /*
+ * Compute implementation requirements and inject implementations.
+ */
+ suite_ids = xmalloc(num_suites * sizeof *suite_ids);
+ br_ssl_client_zero(&cc);
+ br_ssl_engine_set_versions(&cc.eng, vmin, vmax);
+ dnhash = NULL;
+ for (u = 0; hash_functions[u].name; u ++) {
+ const br_hash_class *hc;
+ int id;
+
+ hc = hash_functions[u].hclass;
+ id = (hc->desc >> BR_HASHDESC_ID_OFF) & BR_HASHDESC_ID_MASK;
+ if ((hfuns & ((unsigned)1 << id)) != 0) {
+ dnhash = hc;
+ }
+ }
+ if (dnhash == NULL) {
+ fprintf(stderr, "ERROR: no supported hash function\n");
+ goto client_exit_error;
+ }
+ br_x509_minimal_init(&xc, dnhash,
+ &VEC_ELT(anchors, 0), VEC_LEN(anchors));
+ if (vmin <= BR_TLS11) {
+ if (!(hfuns & (1 << br_md5_ID))) {
+ fprintf(stderr, "ERROR: TLS 1.0 and 1.1 need MD5\n");
+ goto client_exit_error;
+ }
+ if (!(hfuns & (1 << br_sha1_ID))) {
+ fprintf(stderr, "ERROR: TLS 1.0 and 1.1 need SHA-1\n");
+ goto client_exit_error;
+ }
+ }
+ for (u = 0; u < num_suites; u ++) {
+ unsigned req;
+
+ req = suites[u].req;
+ suite_ids[u] = suites[u].suite;
+ if ((req & REQ_TLS12) != 0 && vmax < BR_TLS12) {
+ fprintf(stderr,
+ "ERROR: cipher suite %s requires TLS 1.2\n",
+ suites[u].name);
+ goto client_exit_error;
+ }
+ if ((req & REQ_SHA1) != 0 && !(hfuns & (1 << br_sha1_ID))) {
+ fprintf(stderr,
+ "ERROR: cipher suite %s requires SHA-1\n",
+ suites[u].name);
+ goto client_exit_error;
+ }
+ if ((req & REQ_SHA256) != 0 && !(hfuns & (1 << br_sha256_ID))) {
+ fprintf(stderr,
+ "ERROR: cipher suite %s requires SHA-256\n",
+ suites[u].name);
+ goto client_exit_error;
+ }
+ if ((req & REQ_SHA384) != 0 && !(hfuns & (1 << br_sha384_ID))) {
+ fprintf(stderr,
+ "ERROR: cipher suite %s requires SHA-384\n",
+ suites[u].name);
+ goto client_exit_error;
+ }
+ /* TODO: algorithm implementation selection */
+ if ((req & REQ_AESCBC) != 0) {
+ br_ssl_engine_set_aes_cbc(&cc.eng,
+ &br_aes_ct_cbcenc_vtable,
+ &br_aes_ct_cbcdec_vtable);
+ br_ssl_engine_set_cbc(&cc.eng,
+ &br_sslrec_in_cbc_vtable,
+ &br_sslrec_out_cbc_vtable);
+ }
+ if ((req & REQ_AESGCM) != 0) {
+ br_ssl_engine_set_aes_ctr(&cc.eng,
+ &br_aes_ct_ctr_vtable);
+ br_ssl_engine_set_ghash(&cc.eng,
+ &br_ghash_ctmul);
+ br_ssl_engine_set_gcm(&cc.eng,
+ &br_sslrec_in_gcm_vtable,
+ &br_sslrec_out_gcm_vtable);
+ }
+ if ((req & REQ_3DESCBC) != 0) {
+ br_ssl_engine_set_des_cbc(&cc.eng,
+ &br_des_ct_cbcenc_vtable,
+ &br_des_ct_cbcdec_vtable);
+ br_ssl_engine_set_cbc(&cc.eng,
+ &br_sslrec_in_cbc_vtable,
+ &br_sslrec_out_cbc_vtable);
+ }
+ if ((req & REQ_RSAKEYX) != 0) {
+ br_ssl_client_set_rsapub(&cc, &br_rsa_i31_public);
+ }
+ if ((req & REQ_ECDHE_RSA) != 0) {
+ br_ssl_engine_set_ec(&cc.eng, &br_ec_prime_i31);
+ br_ssl_client_set_rsavrfy(&cc, &br_rsa_i31_pkcs1_vrfy);
+ }
+ if ((req & REQ_ECDHE_ECDSA) != 0) {
+ br_ssl_engine_set_ec(&cc.eng, &br_ec_prime_i31);
+ br_ssl_client_set_ecdsa(&cc, &br_ecdsa_i31_vrfy_asn1);
+ }
+ if ((req & REQ_ECDH) != 0) {
+ br_ssl_engine_set_ec(&cc.eng, &br_ec_prime_i31);
+ }
+ }
+ br_ssl_engine_set_suites(&cc.eng, suite_ids, num_suites);
+
+ for (u = 0; hash_functions[u].name; u ++) {
+ const br_hash_class *hc;
+ int id;
+
+ hc = hash_functions[u].hclass;
+ id = (hc->desc >> BR_HASHDESC_ID_OFF) & BR_HASHDESC_ID_MASK;
+ if ((hfuns & ((unsigned)1 << id)) != 0) {
+ br_ssl_engine_set_hash(&cc.eng, id, hc);
+ br_x509_minimal_set_hash(&xc, id, hc);
+ }
+ }
+ if (vmin <= BR_TLS11) {
+ br_ssl_engine_set_prf10(&cc.eng, &br_tls10_prf);
+ }
+ if (vmax >= BR_TLS12) {
+ if ((hfuns & ((unsigned)1 << br_sha256_ID)) != 0) {
+ br_ssl_engine_set_prf_sha256(&cc.eng,
+ &br_tls12_sha256_prf);
+ }
+ if ((hfuns & ((unsigned)1 << br_sha384_ID)) != 0) {
+ br_ssl_engine_set_prf_sha384(&cc.eng,
+ &br_tls12_sha384_prf);
+ }
+ }
+ 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);
+
+ /*
+ * If there is no provided trust anchor, then certificate validation
+ * will always fail. In that situation, we use our custom wrapper
+ * that tolerates unknown anchors.
+ */
+ if (VEC_LEN(anchors) == 0) {
+ if (verbose) {
+ fprintf(stderr,
+ "WARNING: no configured trust anchor\n");
+ }
+ x509_noanchor_init(&xwc, &xc.vtable);
+ br_ssl_engine_set_x509(&cc.eng, &xwc.vtable);
+ } else {
+ br_ssl_engine_set_x509(&cc.eng, &xc.vtable);
+ }
+
+ br_ssl_engine_set_buffer(&cc.eng, iobuf, iobuf_len, bidi);
+ br_ssl_client_reset(&cc, sni, 0);
+
+ /*
+ * Connect to the peer.
+ */
+ fd = host_connect(host, port, verbose);
+ if (fd < 0) {
+ goto client_exit_error;
+ }
+
+ /*
+ * Run the engine until completion.
+ */
+ if (run_ssl_engine(&cc.eng, fd,
+ (verbose ? RUN_ENGINE_VERBOSE : 0)
+ | (trace ? RUN_ENGINE_TRACE : 0)) != 0)
+ {
+ goto client_exit_error;
+ } else {
+ goto client_exit;
+ }
+
+ /*
+ * Release allocated structures.
+ */
+client_exit:
+ xfree(host);
+ xfree(suites);
+ xfree(suite_ids);
+ VEC_CLEAREXT(anchors, &free_ta_contents);
+ xfree(iobuf);
+ if (fd >= 0) {
+ close(fd);
+ }
+ return retcode;
+
+client_exit_error:
+ retcode = -1;
+ goto client_exit;
+}
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include "brssl.h"
+#include "bearssl.h"
+
+static struct {
+ int err;
+ const char *name;
+ const char *comment;
+} errors[] = {
+ {
+ BR_ERR_BAD_PARAM,
+ "BR_ERR_BAD_PARAM",
+ "Caller-provided parameter is incorrect."
+ }, {
+ BR_ERR_BAD_STATE,
+ "BR_ERR_BAD_STATE",
+ "Operation requested by the caller cannot be applied with"
+ " the current context state (e.g. reading data while"
+ " outgoing data is waiting to be sent)."
+ }, {
+ BR_ERR_UNSUPPORTED_VERSION,
+ "BR_ERR_UNSUPPORTED_VERSION",
+ "Incoming protocol or record version is unsupported."
+ }, {
+ BR_ERR_BAD_VERSION,
+ "BR_ERR_BAD_VERSION",
+ "Incoming record version does not match the expected version."
+ }, {
+ BR_ERR_BAD_LENGTH,
+ "BR_ERR_BAD_LENGTH",
+ "Incoming record length is invalid."
+ }, {
+ BR_ERR_TOO_LARGE,
+ "BR_ERR_TOO_LARGE",
+ "Incoming record is too large to be processed, or buffer"
+ " is too small for the handshake message to send."
+ }, {
+ BR_ERR_BAD_MAC,
+ "BR_ERR_BAD_MAC",
+ "Decryption found an invalid padding, or the record MAC is"
+ " not correct."
+ }, {
+ BR_ERR_NO_RANDOM,
+ "BR_ERR_NO_RANDOM",
+ "No initial entropy was provided, and none can be obtained"
+ " from the OS."
+ }, {
+ BR_ERR_UNKNOWN_TYPE,
+ "BR_ERR_UNKNOWN_TYPE",
+ "Incoming record type is unknown."
+ }, {
+ BR_ERR_UNEXPECTED,
+ "BR_ERR_UNEXPECTED",
+ "Incoming record or message has wrong type with regards to"
+ " the current engine state."
+ }, {
+ BR_ERR_BAD_CCS,
+ "BR_ERR_BAD_CCS",
+ "ChangeCipherSpec message from the peer has invalid contents."
+ }, {
+ BR_ERR_BAD_ALERT,
+ "BR_ERR_BAD_ALERT",
+ "Alert message from the peer has invalid contents"
+ " (odd length)."
+ }, {
+ BR_ERR_BAD_HANDSHAKE,
+ "BR_ERR_BAD_HANDSHAKE",
+ "Incoming handshake message decoding failed."
+ }, {
+ BR_ERR_OVERSIZED_ID,
+ "BR_ERR_OVERSIZED_ID",
+ "ServerHello contains a session ID which is larger than"
+ " 32 bytes."
+ }, {
+ BR_ERR_BAD_CIPHER_SUITE,
+ "BR_ERR_BAD_CIPHER_SUITE",
+ "Server wants to use a cipher suite that we did not claim"
+ " to support. This is also reported if we tried to advertise"
+ " a cipher suite that we do not support."
+ }, {
+ BR_ERR_BAD_COMPRESSION,
+ "BR_ERR_BAD_COMPRESSION",
+ "Server wants to use a compression that we did not claim"
+ " to support."
+ }, {
+ BR_ERR_BAD_FRAGLEN,
+ "BR_ERR_BAD_FRAGLEN",
+ "Server's max fragment length does not match client's."
+ }, {
+ BR_ERR_BAD_SECRENEG,
+ "BR_ERR_BAD_SECRENEG",
+ "Secure renegotiation failed."
+ }, {
+ BR_ERR_EXTRA_EXTENSION,
+ "BR_ERR_EXTRA_EXTENSION",
+ "Server sent an extension type that we did not announce,"
+ " or used the same extension type several times in a"
+ " single ServerHello."
+ }, {
+ BR_ERR_BAD_SNI,
+ "BR_ERR_BAD_SNI",
+ "Invalid Server Name Indication contents (when used by"
+ " the server, this extension shall be empty)."
+ }, {
+ BR_ERR_BAD_HELLO_DONE,
+ "BR_ERR_BAD_HELLO_DONE",
+ "Invalid ServerHelloDone from the server (length is not 0)."
+ }, {
+ BR_ERR_LIMIT_EXCEEDED,
+ "BR_ERR_LIMIT_EXCEEDED",
+ "Internal limit exceeded (e.g. server's public key is too"
+ " large)."
+ }, {
+ BR_ERR_BAD_FINISHED,
+ "BR_ERR_BAD_FINISHED",
+ "Finished message from peer does not match the expected"
+ " value."
+ }, {
+ BR_ERR_RESUME_MISMATCH,
+ "BR_ERR_RESUME_MISMATCH",
+ "Session resumption attempt with distinct version or cipher"
+ " suite."
+ }, {
+ BR_ERR_INVALID_ALGORITHM,
+ "BR_ERR_INVALID_ALGORITHM",
+ "Unsupported or invalid algorithm (ECDHE curve, signature"
+ " algorithm, hash function)."
+ }, {
+ BR_ERR_BAD_SIGNATURE,
+ "BR_ERR_BAD_SIGNATURE",
+ "Invalid signature on ServerKeyExchange message."
+ }, {
+ BR_ERR_IO,
+ "BR_ERR_IO",
+ "I/O error or premature close on transport stream."
+ }, {
+ BR_ERR_X509_INVALID_VALUE,
+ "BR_ERR_X509_INVALID_VALUE",
+ "Invalid value in an ASN.1 structure."
+ },
+ {
+ BR_ERR_X509_TRUNCATED,
+ "BR_ERR_X509_TRUNCATED",
+ "Truncated certificate or other ASN.1 object."
+ },
+ {
+ BR_ERR_X509_EMPTY_CHAIN,
+ "BR_ERR_X509_EMPTY_CHAIN",
+ "Empty certificate chain (no certificate at all)."
+ },
+ {
+ BR_ERR_X509_INNER_TRUNC,
+ "BR_ERR_X509_INNER_TRUNC",
+ "Decoding error: inner element extends beyond outer element"
+ " size."
+ },
+ {
+ BR_ERR_X509_BAD_TAG_CLASS,
+ "BR_ERR_X509_BAD_TAG_CLASS",
+ "Decoding error: unsupported tag class (application or"
+ " private)."
+ },
+ {
+ BR_ERR_X509_BAD_TAG_VALUE,
+ "BR_ERR_X509_BAD_TAG_VALUE",
+ "Decoding error: unsupported tag value."
+ },
+ {
+ BR_ERR_X509_INDEFINITE_LENGTH,
+ "BR_ERR_X509_INDEFINITE_LENGTH",
+ "Decoding error: indefinite length."
+ },
+ {
+ BR_ERR_X509_EXTRA_ELEMENT,
+ "BR_ERR_X509_EXTRA_ELEMENT",
+ "Decoding error: extraneous element."
+ },
+ {
+ BR_ERR_X509_UNEXPECTED,
+ "BR_ERR_X509_UNEXPECTED",
+ "Decoding error: unexpected element."
+ },
+ {
+ BR_ERR_X509_NOT_CONSTRUCTED,
+ "BR_ERR_X509_NOT_CONSTRUCTED",
+ "Decoding error: expected constructed element, but is"
+ " primitive."
+ },
+ {
+ BR_ERR_X509_NOT_PRIMITIVE,
+ "BR_ERR_X509_NOT_PRIMITIVE",
+ "Decoding error: expected primitive element, but is"
+ " constructed."
+ },
+ {
+ BR_ERR_X509_PARTIAL_BYTE,
+ "BR_ERR_X509_PARTIAL_BYTE",
+ "Decoding error: BIT STRING length is not multiple of 8."
+ },
+ {
+ BR_ERR_X509_BAD_BOOLEAN,
+ "BR_ERR_X509_BAD_BOOLEAN",
+ "Decoding error: BOOLEAN value has invalid length."
+ },
+ {
+ BR_ERR_X509_OVERFLOW,
+ "BR_ERR_X509_OVERFLOW",
+ "Decoding error: value is off-limits."
+ },
+ {
+ BR_ERR_X509_BAD_DN,
+ "BR_ERR_X509_BAD_DN",
+ "Invalid distinguished name."
+ },
+ {
+ BR_ERR_X509_BAD_TIME,
+ "BR_ERR_X509_BAD_TIME",
+ "Invalid date/time representation."
+ },
+ {
+ BR_ERR_X509_UNSUPPORTED,
+ "BR_ERR_X509_UNSUPPORTED",
+ "Certificate contains unsupported features that cannot be"
+ " ignored."
+ },
+ {
+ BR_ERR_X509_LIMIT_EXCEEDED,
+ "BR_ERR_X509_LIMIT_EXCEEDED",
+ "Key or signature size exceeds internal limits."
+ },
+ {
+ BR_ERR_X509_WRONG_KEY_TYPE,
+ "BR_ERR_X509_WRONG_KEY_TYPE",
+ "Key type does not match that which was expected."
+ },
+ {
+ BR_ERR_X509_BAD_SIGNATURE,
+ "BR_ERR_X509_BAD_SIGNATURE",
+ "Signature is invalid."
+ },
+ {
+ BR_ERR_X509_TIME_UNKNOWN,
+ "BR_ERR_X509_TIME_UNKNOWN",
+ "Validation time is unknown."
+ },
+ {
+ BR_ERR_X509_EXPIRED,
+ "BR_ERR_X509_EXPIRED",
+ "Certificate is expired or not yet valid."
+ },
+ {
+ BR_ERR_X509_DN_MISMATCH,
+ "BR_ERR_X509_DN_MISMATCH",
+ "Issuer/Subject DN mismatch in the chain."
+ },
+ {
+ BR_ERR_X509_BAD_SERVER_NAME,
+ "BR_ERR_X509_BAD_SERVER_NAME",
+ "Expected server name was not found in the chain."
+ },
+ {
+ BR_ERR_X509_CRITICAL_EXTENSION,
+ "BR_ERR_X509_CRITICAL_EXTENSION",
+ "Unknown critical extension in certificate."
+ },
+ {
+ BR_ERR_X509_NOT_CA,
+ "BR_ERR_X509_NOT_CA",
+ "Not a CA, or path length constraint violation."
+ },
+ {
+ BR_ERR_X509_FORBIDDEN_KEY_USAGE,
+ "BR_ERR_X509_FORBIDDEN_KEY_USAGE",
+ "Key Usage extension prohibits intended usage."
+ },
+ {
+ BR_ERR_X509_WEAK_PUBLIC_KEY,
+ "BR_ERR_X509_WEAK_PUBLIC_KEY",
+ "Public key found in certificate is too small."
+ },
+ {
+ BR_ERR_X509_NOT_TRUSTED,
+ "BR_ERR_X509_NOT_TRUSTED",
+ "Chain could not be linked to a trust anchor."
+ },
+ { 0, 0, 0 }
+};
+
+/* see brssl.h */
+const char *
+find_error_name(int err, const char **comment)
+{
+ size_t u;
+
+ for (u = 0; errors[u].name; u ++) {
+ if (errors[u].err == err) {
+ if (comment != NULL) {
+ *comment = errors[u].comment;
+ }
+ return errors[u].name;
+ }
+ }
+ return NULL;
+}
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include "brssl.h"
+
+/* see brssl.h */
+unsigned char *
+read_file(const char *fname, size_t *len)
+{
+ bvector vbuf = VEC_INIT;
+ FILE *f;
+
+ *len = 0;
+ f = fopen(fname, "rb");
+ if (f == NULL) {
+ fprintf(stderr,
+ "ERROR: could not open file '%s' for reading\n", fname);
+ return NULL;
+ }
+ for (;;) {
+ unsigned char tmp[1024];
+ size_t rlen;
+
+ rlen = fread(tmp, 1, sizeof tmp, f);
+ if (rlen == 0) {
+ unsigned char *buf;
+
+ if (ferror(f)) {
+ fprintf(stderr,
+ "ERROR: read error on file '%s'\n",
+ fname);
+ fclose(f);
+ return NULL;
+ }
+ buf = VEC_TOARRAY(vbuf);
+ *len = VEC_LEN(vbuf);
+ VEC_CLEAR(vbuf);
+ fclose(f);
+ return buf;
+ }
+ VEC_ADDMANY(vbuf, tmp, rlen);
+ }
+}
+
+/* see brssl.h */
+int
+write_file(const char *fname, const void *data, size_t len)
+{
+ FILE *f;
+ const unsigned char *buf;
+
+ f = fopen(fname, "wb");
+ if (f == NULL) {
+ fprintf(stderr,
+ "ERROR: could not open file '%s' for reading\n", fname);
+ return -1;
+ }
+ buf = data;
+ while (len > 0) {
+ size_t wlen;
+
+ wlen = fwrite(buf, 1, len, f);
+ if (wlen == 0) {
+ fprintf(stderr,
+ "ERROR: could not write all bytes to '%s'\n",
+ fname);
+ fclose(f);
+ return -1;
+ }
+ buf += wlen;
+ len -= wlen;
+ }
+ if (ferror(f)) {
+ fprintf(stderr, "ERROR: write error on file '%s'\n", fname);
+ fclose(f);
+ return -1;
+ }
+ fclose(f);
+ return 0;
+}
+
+/* see brssl.h */
+int
+looks_like_DER(const unsigned char *buf, size_t len)
+{
+ int fb;
+ size_t dlen;
+
+ if (len < 2) {
+ return 0;
+ }
+ if (*buf ++ != 0x30) {
+ return 0;
+ }
+ fb = *buf ++;
+ len -= 2;
+ if (fb < 0x80) {
+ return (size_t)fb == len;
+ } else if (fb == 0x80) {
+ return 0;
+ } else {
+ fb -= 0x80;
+ if (len < (size_t)fb + 2) {
+ return 0;
+ }
+ len -= (size_t)fb;
+ dlen = 0;
+ while (fb -- > 0) {
+ if (dlen > (len >> 8)) {
+ return 0;
+ }
+ dlen = (dlen << 8) + (size_t)*buf ++;
+ }
+ return dlen == len;
+ }
+}
+
+static void
+vblob_append(void *cc, const void *data, size_t len)
+{
+ bvector *bv;
+
+ bv = cc;
+ VEC_ADDMANY(*bv, data, len);
+}
+
+/* see brssl.h */
+void
+free_pem_object_contents(pem_object *po)
+{
+ if (po != NULL) {
+ xfree(po->name);
+ xfree(po->data);
+ }
+}
+
+/* see brssl.h */
+pem_object *
+decode_pem(const void *src, size_t len, size_t *num)
+{
+ VECTOR(pem_object) pem_list = VEC_INIT;
+ br_pem_decoder_context pc;
+ pem_object po, *pos;
+ const unsigned char *buf;
+ bvector bv = VEC_INIT;
+ int inobj;
+
+ br_pem_decoder_init(&pc);
+ buf = src;
+ inobj = 0;
+ po.name = NULL;
+ po.data = NULL;
+ po.data_len = 0;
+ while (len > 0) {
+ size_t tlen;
+
+ tlen = br_pem_decoder_push(&pc, buf, len);
+ buf += tlen;
+ len -= tlen;
+ switch (br_pem_decoder_event(&pc)) {
+
+ case BR_PEM_BEGIN_OBJ:
+ po.name = xstrdup(br_pem_decoder_name(&pc));
+ br_pem_decoder_setdest(&pc, vblob_append, &bv);
+ inobj = 1;
+ break;
+
+ case BR_PEM_END_OBJ:
+ if (inobj) {
+ po.data = VEC_TOARRAY(bv);
+ po.data_len = VEC_LEN(bv);
+ VEC_ADD(pem_list, po);
+ VEC_CLEAR(bv);
+ po.name = NULL;
+ po.data = NULL;
+ po.data_len = 0;
+ inobj = 0;
+ }
+ break;
+
+ case BR_PEM_ERROR:
+ xfree(po.name);
+ VEC_CLEAR(bv);
+ fprintf(stderr,
+ "ERROR: invalid PEM encoding\n");
+ VEC_CLEAREXT(pem_list, &free_pem_object_contents);
+ return NULL;
+ }
+ }
+ if (inobj) {
+ fprintf(stderr, "ERROR: unfinished PEM object\n");
+ xfree(po.name);
+ VEC_CLEAR(bv);
+ VEC_CLEAREXT(pem_list, &free_pem_object_contents);
+ return NULL;
+ }
+
+ *num = VEC_LEN(pem_list);
+ VEC_ADD(pem_list, po);
+ pos = VEC_TOARRAY(pem_list);
+ VEC_CLEAR(pem_list);
+ return pos;
+}
+
+/* see brssl.h */
+br_x509_certificate *
+read_certificates(const char *fname, size_t *num)
+{
+ VECTOR(br_x509_certificate) cert_list = VEC_INIT;
+ unsigned char *buf;
+ size_t len;
+ pem_object *pos;
+ size_t u, num_pos;
+ br_x509_certificate *xcs;
+ br_x509_certificate dummy;
+
+ *num = 0;
+
+ /*
+ * TODO: reading the whole file is crude; we could parse them
+ * in a streamed fashion. But it does not matter much in practice.
+ */
+ buf = read_file(fname, &len);
+ if (buf == NULL) {
+ return NULL;
+ }
+
+ /*
+ * Check for a DER-encoded certificate.
+ */
+ if (looks_like_DER(buf, len)) {
+ xcs = xmalloc(2 * sizeof *xcs);
+ xcs[0].data = buf;
+ xcs[0].data_len = len;
+ xcs[1].data = NULL;
+ xcs[1].data_len = 0;
+ *num = 1;
+ return xcs;
+ }
+
+ pos = decode_pem(buf, len, &num_pos);
+ xfree(buf);
+ for (u = 0; u < num_pos; u ++) {
+ if (eqstr(pos[u].name, "CERTIFICATE")
+ || eqstr(pos[u].name, "X509 CERTIFICATE"))
+ {
+ br_x509_certificate xc;
+
+ xc.data = pos[u].data;
+ xc.data_len = pos[u].data_len;
+ pos[u].data = NULL;
+ VEC_ADD(cert_list, xc);
+ }
+ }
+ for (u = 0; u < num_pos; u ++) {
+ free_pem_object_contents(&pos[u]);
+ }
+ xfree(pos);
+
+ if (VEC_LEN(cert_list) == 0) {
+ fprintf(stderr, "ERROR: no certificate in file '%s'\n", fname);
+ return NULL;
+ }
+ *num = VEC_LEN(cert_list);
+ dummy.data = NULL;
+ dummy.data_len = 0;
+ VEC_ADD(cert_list, dummy);
+ xcs = VEC_TOARRAY(cert_list);
+ VEC_CLEAR(cert_list);
+ return xcs;
+}
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include "brssl.h"
+#include "bearssl.h"
+
+static private_key *
+decode_key(const unsigned char *buf, size_t len)
+{
+ br_skey_decoder_context dc;
+ int err;
+ private_key *sk;
+
+ br_skey_decoder_init(&dc);
+ br_skey_decoder_push(&dc, buf, len);
+ err = br_skey_decoder_last_error(&dc);
+ if (err != 0) {
+ const char *errname, *errmsg;
+
+ fprintf(stderr, "ERROR (decoding): err=%d\n", err);
+ errname = find_error_name(err, &errmsg);
+ if (errname != NULL) {
+ fprintf(stderr, " %s: %s\n", errname, errmsg);
+ } else {
+ fprintf(stderr, " (unknown)\n");
+ }
+ return NULL;
+ }
+ switch (br_skey_decoder_key_type(&dc)) {
+ const br_rsa_private_key *rk;
+ const br_ec_private_key *ek;
+
+ case BR_KEYTYPE_RSA:
+ rk = br_skey_decoder_get_rsa(&dc);
+ sk = xmalloc(sizeof *sk);
+ sk->key_type = BR_KEYTYPE_RSA;
+ sk->key.rsa.n_bitlen = rk->n_bitlen;
+ sk->key.rsa.p = xblobdup(rk->p, rk->plen);
+ sk->key.rsa.plen = rk->plen;
+ sk->key.rsa.q = xblobdup(rk->q, rk->qlen);
+ sk->key.rsa.qlen = rk->qlen;
+ sk->key.rsa.dp = xblobdup(rk->dp, rk->dplen);
+ sk->key.rsa.dplen = rk->dplen;
+ sk->key.rsa.dq = xblobdup(rk->dq, rk->dqlen);
+ sk->key.rsa.dqlen = rk->dqlen;
+ sk->key.rsa.iq = xblobdup(rk->iq, rk->iqlen);
+ sk->key.rsa.iqlen = rk->iqlen;
+ break;
+
+ case BR_KEYTYPE_EC:
+ ek = br_skey_decoder_get_ec(&dc);
+ sk = xmalloc(sizeof *sk);
+ sk->key_type = BR_KEYTYPE_EC;
+ sk->key.ec.curve = ek->curve;
+ sk->key.ec.x = xblobdup(ek->x, ek->xlen);
+ sk->key.ec.xlen = ek->xlen;
+ break;
+
+ default:
+ fprintf(stderr, "Unknown key type: %d\n",
+ br_skey_decoder_key_type(&dc));
+ sk = NULL;
+ break;
+ }
+
+ return sk;
+}
+
+/* see brssl.h */
+private_key *
+read_private_key(const char *fname)
+{
+ unsigned char *buf;
+ size_t len;
+ private_key *sk;
+ pem_object *pos;
+ size_t num, u;
+
+ buf = NULL;
+ pos = NULL;
+ sk = NULL;
+ buf = read_file(fname, &len);
+ if (buf == NULL) {
+ goto deckey_exit;
+ }
+ if (looks_like_DER(buf, len)) {
+ sk = decode_key(buf, len);
+ goto deckey_exit;
+ } else {
+ pos = decode_pem(buf, len, &num);
+ if (pos == NULL) {
+ goto deckey_exit;
+ }
+ for (u = 0; pos[u].name; u ++) {
+ const char *name;
+
+ name = pos[u].name;
+ if (eqstr(name, "RSA PRIVATE KEY")
+ || eqstr(name, "EC PRIVATE KEY")
+ || eqstr(name, "PRIVATE KEY"))
+ {
+ sk = decode_key(pos[u].data, pos[u].data_len);
+ goto deckey_exit;
+ }
+ }
+ fprintf(stderr, "ERROR: no private key in file '%s'\n", fname);
+ goto deckey_exit;
+ }
+
+deckey_exit:
+ if (buf != NULL) {
+ xfree(buf);
+ }
+ if (pos != NULL) {
+ for (u = 0; pos[u].name; u ++) {
+ free_pem_object_contents(&pos[u]);
+ }
+ xfree(pos);
+ }
+ return sk;
+}
+
+/* see brssl.h */
+void
+free_private_key(private_key *sk)
+{
+ if (sk == NULL) {
+ return;
+ }
+ switch (sk->key_type) {
+ case BR_KEYTYPE_RSA:
+ xfree(sk->key.rsa.p);
+ xfree(sk->key.rsa.q);
+ xfree(sk->key.rsa.dp);
+ xfree(sk->key.rsa.dq);
+ xfree(sk->key.rsa.iq);
+ break;
+ case BR_KEYTYPE_EC:
+ xfree(sk->key.ec.x);
+ break;
+ }
+ xfree(sk);
+}
--- /dev/null
+/*
+ * 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 "brssl.h"
+#include "bearssl.h"
+
+/* see brssl.h */
+const protocol_version protocol_versions[] = {
+ { "tls10", BR_TLS10, "TLS 1.0" },
+ { "tls11", BR_TLS11, "TLS 1.1" },
+ { "tls12", BR_TLS12, "TLS 1.2" },
+ { NULL, 0, NULL }
+};
+
+/* see brssl.h */
+const hash_function hash_functions[] = {
+ { "md5", &br_md5_vtable, "MD5" },
+ { "sha1", &br_sha1_vtable, "SHA-1" },
+ { "sha224", &br_sha224_vtable, "SHA-224" },
+ { "sha256", &br_sha256_vtable, "SHA-256" },
+ { "sha384", &br_sha384_vtable, "SHA-384" },
+ { "sha512", &br_sha512_vtable, "SHA-512" },
+ { NULL, 0, NULL }
+};
+
+/* see brssl.h */
+const cipher_suite cipher_suites[] = {
+ {
+ "ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ REQ_ECDHE_ECDSA | REQ_AESGCM | REQ_SHA256 | REQ_TLS12,
+ "ECDHE with ECDSA, AES-128/GCM encryption (TLS 1.2+)"
+ },
+ {
+ "ECDHE_RSA_WITH_AES_128_GCM_SHA256",
+ BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ REQ_ECDHE_RSA | REQ_AESGCM | REQ_SHA256 | REQ_TLS12,
+ "ECDHE with RSA, AES-128/GCM encryption (TLS 1.2+)"
+ },
+ {
+ "ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ REQ_ECDHE_ECDSA | REQ_AESGCM | REQ_SHA384 | REQ_TLS12,
+ "ECDHE with ECDSA, AES-256/GCM encryption (TLS 1.2+)"
+ },
+ {
+ "ECDHE_RSA_WITH_AES_256_GCM_SHA384",
+ BR_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ REQ_ECDHE_RSA | REQ_AESGCM | REQ_SHA384 | REQ_TLS12,
+ "ECDHE with RSA, AES-256/GCM encryption (TLS 1.2+)"
+ },
+ {
+ "ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+ REQ_ECDHE_ECDSA | REQ_AESCBC | REQ_SHA256 | REQ_TLS12,
+ "ECDHE with ECDSA, AES-128/CBC + SHA-256 (TLS 1.2+)"
+ },
+ {
+ "ECDHE_RSA_WITH_AES_128_CBC_SHA256",
+ BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+ REQ_ECDHE_RSA | REQ_AESCBC | REQ_SHA256 | REQ_TLS12,
+ "ECDHE with RSA, AES-128/CBC + SHA-256 (TLS 1.2+)"
+ },
+ {
+ "ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
+ REQ_ECDHE_ECDSA | REQ_AESCBC | REQ_SHA384 | REQ_TLS12,
+ "ECDHE with ECDSA, AES-256/CBC + SHA-384 (TLS 1.2+)"
+ },
+ {
+ "ECDHE_RSA_WITH_AES_256_CBC_SHA384",
+ BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
+ REQ_ECDHE_RSA | REQ_AESCBC | REQ_SHA384 | REQ_TLS12,
+ "ECDHE with RSA, AES-256/CBC + SHA-384 (TLS 1.2+)"
+ },
+ {
+ "ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ REQ_ECDHE_ECDSA | REQ_AESCBC | REQ_SHA1,
+ "ECDHE with ECDSA, AES-128/CBC + SHA-1"
+ },
+ {
+ "ECDHE_RSA_WITH_AES_128_CBC_SHA",
+ BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ REQ_ECDHE_RSA | REQ_AESCBC | REQ_SHA1,
+ "ECDHE with RSA, AES-128/CBC + SHA-1"
+ },
+ {
+ "ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ REQ_ECDHE_ECDSA | REQ_AESCBC | REQ_SHA1,
+ "ECDHE with ECDSA, AES-256/CBC + SHA-1"
+ },
+ {
+ "ECDHE_RSA_WITH_AES_256_CBC_SHA",
+ BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ REQ_ECDHE_RSA | REQ_AESCBC | REQ_SHA1,
+ "ECDHE with RSA, AES-256/CBC + SHA-1"
+ },
+ {
+ "ECDH_ECDSA_WITH_AES_128_GCM_SHA256",
+ BR_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,
+ REQ_ECDH | REQ_AESGCM | REQ_SHA256 | REQ_TLS12,
+ "ECDH key exchange (EC cert), AES-128/GCM (TLS 1.2+)"
+ },
+ {
+ "ECDH_RSA_WITH_AES_128_GCM_SHA256",
+ BR_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,
+ REQ_ECDH | REQ_AESGCM | REQ_SHA256 | REQ_TLS12,
+ "ECDH key exchange (RSA cert), AES-128/GCM (TLS 1.2+)"
+ },
+ {
+ "ECDH_ECDSA_WITH_AES_256_GCM_SHA384",
+ BR_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384,
+ REQ_ECDH | REQ_AESGCM | REQ_SHA384 | REQ_TLS12,
+ "ECDH key exchange (EC cert), AES-256/GCM (TLS 1.2+)"
+ },
+ {
+ "ECDH_RSA_WITH_AES_256_GCM_SHA384",
+ BR_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384,
+ REQ_ECDH | REQ_AESGCM | REQ_SHA384 | REQ_TLS12,
+ "ECDH key exchange (RSA cert), AES-256/GCM (TLS 1.2+)"
+ },
+ {
+ "ECDH_ECDSA_WITH_AES_128_CBC_SHA256",
+ BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
+ REQ_ECDH | REQ_AESCBC | REQ_SHA256 | REQ_TLS12,
+ "ECDH key exchange (EC cert), AES-128/CBC + HMAC/SHA-256 (TLS 1.2+)"
+ },
+ {
+ "ECDH_RSA_WITH_AES_128_CBC_SHA256",
+ BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
+ REQ_ECDH | REQ_AESCBC | REQ_SHA256 | REQ_TLS12,
+ "ECDH key exchange (RSA cert), AES-128/CBC + HMAC/SHA-256 (TLS 1.2+)"
+ },
+ {
+ "ECDH_ECDSA_WITH_AES_256_CBC_SHA384",
+ BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,
+ REQ_ECDH | REQ_AESCBC | REQ_SHA384 | REQ_TLS12,
+ "ECDH key exchange (EC cert), AES-256/CBC + HMAC/SHA-384 (TLS 1.2+)"
+ },
+ {
+ "ECDH_RSA_WITH_AES_256_CBC_SHA384",
+ BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,
+ REQ_ECDH | REQ_AESCBC | REQ_SHA384 | REQ_TLS12,
+ "ECDH key exchange (RSA cert), AES-256/CBC + HMAC/SHA-384 (TLS 1.2+)"
+ },
+ {
+ "ECDH_ECDSA_WITH_AES_128_CBC_SHA",
+ BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
+ REQ_ECDH | REQ_AESCBC | REQ_SHA1,
+ "ECDH key exchange (EC cert), AES-128/CBC + HMAC/SHA-1"
+ },
+ {
+ "ECDH_RSA_WITH_AES_128_CBC_SHA",
+ BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
+ REQ_ECDH | REQ_AESCBC | REQ_SHA1,
+ "ECDH key exchange (RSA cert), AES-128/CBC + HMAC/SHA-1"
+ },
+ {
+ "ECDH_ECDSA_WITH_AES_256_CBC_SHA",
+ BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
+ REQ_ECDH | REQ_AESCBC | REQ_SHA1,
+ "ECDH key exchange (EC cert), AES-256/CBC + HMAC/SHA-1"
+ },
+ {
+ "ECDH_RSA_WITH_AES_256_CBC_SHA",
+ BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
+ REQ_ECDH | REQ_AESCBC | REQ_SHA1,
+ "ECDH key exchange (RSA cert), AES-256/CBC + HMAC/SHA-1"
+ },
+ {
+ "RSA_WITH_AES_128_GCM_SHA256",
+ BR_TLS_RSA_WITH_AES_128_GCM_SHA256,
+ REQ_RSAKEYX | REQ_AESGCM | REQ_SHA256 | REQ_TLS12,
+ "RSA key exchange, AES-128/GCM encryption (TLS 1.2+)"
+ },
+ {
+ "RSA_WITH_AES_256_GCM_SHA384",
+ BR_TLS_RSA_WITH_AES_256_GCM_SHA384,
+ REQ_RSAKEYX | REQ_AESGCM | REQ_SHA384 | REQ_TLS12,
+ "RSA key exchange, AES-256/GCM encryption (TLS 1.2+)"
+ },
+ {
+ "RSA_WITH_AES_128_CBC_SHA256",
+ BR_TLS_RSA_WITH_AES_128_CBC_SHA256,
+ REQ_RSAKEYX | REQ_AESCBC | REQ_SHA256 | REQ_TLS12,
+ "RSA key exchange, AES-128/CBC + HMAC/SHA-256 (TLS 1.2+)"
+ },
+ {
+ "RSA_WITH_AES_256_CBC_SHA256",
+ BR_TLS_RSA_WITH_AES_256_CBC_SHA256,
+ REQ_RSAKEYX | REQ_AESCBC | REQ_SHA256 | REQ_TLS12,
+ "RSA key exchange, AES-256/CBC + HMAC/SHA-256 (TLS 1.2+)"
+ },
+ {
+ "RSA_WITH_AES_128_CBC_SHA",
+ BR_TLS_RSA_WITH_AES_128_CBC_SHA,
+ REQ_RSAKEYX | REQ_AESCBC | REQ_SHA1,
+ "RSA key exchange, AES-128/CBC + HMAC/SHA-1"
+ },
+ {
+ "RSA_WITH_AES_256_CBC_SHA",
+ BR_TLS_RSA_WITH_AES_256_CBC_SHA,
+ REQ_RSAKEYX | REQ_AESCBC | REQ_SHA1,
+ "RSA key exchange, AES-256/CBC + HMAC/SHA-1"
+ },
+ {
+ "ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
+ BR_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ REQ_ECDHE_ECDSA | REQ_3DESCBC | REQ_SHA1,
+ "ECDHE with ECDSA, 3DES/CBC + SHA-1"
+ },
+ {
+ "ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
+ BR_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ REQ_ECDHE_RSA | REQ_3DESCBC | REQ_SHA1,
+ "ECDHE with RSA, 3DES/CBC + SHA-1"
+ },
+ {
+ "ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA",
+ BR_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ REQ_ECDH | REQ_3DESCBC | REQ_SHA1,
+ "ECDH key exchange (EC cert), 3DES/CBC + HMAC/SHA-1"
+ },
+ {
+ "ECDH_RSA_WITH_3DES_EDE_CBC_SHA",
+ BR_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
+ REQ_ECDH | REQ_3DESCBC | REQ_SHA1,
+ "ECDH key exchange (RSA cert), 3DES/CBC + HMAC/SHA-1"
+ },
+ {
+ "RSA_WITH_3DES_EDE_CBC_SHA",
+ BR_TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+ REQ_RSAKEYX | REQ_3DESCBC | REQ_SHA1,
+ "RSA key exchange, 3DES/CBC + HMAC/SHA-1"
+ },
+ { NULL, 0, 0, NULL }
+};
+
+/* see brssl.h */
+const char *
+get_suite_name(unsigned suite)
+{
+ size_t u;
+
+ for (u = 0; cipher_suites[u].name; u ++) {
+ if (cipher_suites[u].suite == suite) {
+ return cipher_suites[u].name;
+ }
+ }
+ return NULL;
+}
+
+/* see brssl.h */
+int
+get_suite_name_ext(unsigned suite, char *dst, size_t len)
+{
+ const char *name;
+ char tmp[30];
+ size_t n;
+
+ name = get_suite_name(suite);
+ if (name == NULL) {
+ sprintf(tmp, "unknown (0x%04X)", suite);
+ name = tmp;
+ }
+ n = 1 + strlen(name);
+ if (n > len) {
+ if (len > 0) {
+ dst[0] = 0;
+ }
+ return -1;
+ }
+ memcpy(dst, name, n);
+ return 0;
+}
+
+/* see brssl.h */
+void
+list_names(void)
+{
+ size_t u;
+
+ printf("Protocol versions:\n");
+ for (u = 0; protocol_versions[u].name; u ++) {
+ printf(" %-8s %s\n",
+ protocol_versions[u].name,
+ protocol_versions[u].comment);
+ }
+ printf("Hash functions:\n");
+ for (u = 0; hash_functions[u].name; u ++) {
+ printf(" %-8s %s\n",
+ hash_functions[u].name,
+ hash_functions[u].comment);
+ }
+ printf("Cipher suites:\n");
+ for (u = 0; cipher_suites[u].name; u ++) {
+ printf(" %s\n %s\n",
+ cipher_suites[u].name,
+ cipher_suites[u].comment);
+ }
+}
+
+static int
+is_ign(int c)
+{
+ if (c == 0) {
+ return 0;
+ }
+ if (c <= 32 || c == '-' || c == '_' || c == '.'
+ || c == '/' || c == '+' || c == ':')
+ {
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Get next non-ignored character, normalised:
+ * ASCII letters are converted to lowercase
+ * control characters, space, '-', '_', '.', '/', '+' and ':' are ignored
+ * A terminating zero is returned as 0.
+ */
+static int
+next_char(const char **ps, const char *limit)
+{
+ for (;;) {
+ int c;
+
+ if (*ps == limit) {
+ return 0;
+ }
+ c = *(*ps) ++;
+ if (c == 0) {
+ return 0;
+ }
+ if (c >= 'A' && c <= 'Z') {
+ c += 'a' - 'A';
+ }
+ if (!is_ign(c)) {
+ return c;
+ }
+ }
+}
+
+/*
+ * Partial string equality comparison, with normalisation.
+ */
+static int
+eqstr_chunk(const char *s1, size_t s1_len, const char *s2, size_t s2_len)
+{
+ const char *lim1, *lim2;
+
+ lim1 = s1 + s1_len;
+ lim2 = s2 + s2_len;
+ for (;;) {
+ int c1, c2;
+
+ c1 = next_char(&s1, lim1);
+ c2 = next_char(&s2, lim2);
+ if (c1 != c2) {
+ return 0;
+ }
+ if (c1 == 0) {
+ return 1;
+ }
+ }
+ return 1;
+}
+
+/* see brssl.h */
+int
+eqstr(const char *s1, const char *s2)
+{
+ return eqstr_chunk(s1, strlen(s1), s2, strlen(s2));
+}
+
+/*
+ * Comma-separated list enumeration. This returns a pointer to the first
+ * word in the string, skipping leading ignored characters. '*len' is
+ * set to the word length (not counting trailing ignored characters).
+ * '*str' is updated to point to immediately after the next comma, or to
+ * the terminating zero, whichever comes first.
+ *
+ * Empty words are skipped. If there is no next non-empty word, then this
+ * function returns NULL and sets *len to 0.
+ */
+static const char *
+next_word(const char **str, size_t *len)
+{
+ int c;
+ const char *begin;
+ size_t u;
+
+ /*
+ * Find next non-ignored character which is not a comma.
+ */
+ for (;;) {
+ c = **str;
+ if (c == 0) {
+ *len = 0;
+ return NULL;
+ }
+ if (!is_ign(c) && c != ',') {
+ break;
+ }
+ (*str) ++;
+ }
+
+ /*
+ * Find next comma or terminator.
+ */
+ begin = *str;
+ for (;;) {
+ c = *(*str);
+ if (c == 0 || c == ',') {
+ break;
+ }
+ (*str) ++;
+ }
+
+ /*
+ * Remove trailing ignored characters.
+ */
+ u = (size_t)(*str - begin);
+ while (u > 0 && is_ign(begin[u - 1])) {
+ u --;
+ }
+ if (c == ',') {
+ (*str) ++;
+ }
+ *len = u;
+ return begin;
+}
+
+/* see brssl.h */
+unsigned
+parse_version(const char *name, size_t len)
+{
+ size_t u;
+
+ for (u = 0;; u ++) {
+ const char *ref;
+
+ ref = protocol_versions[u].name;
+ if (ref == NULL) {
+ fprintf(stderr, "ERROR: unrecognised protocol"
+ " version name: '%s'\n", name);
+ return 0;
+ }
+ if (eqstr_chunk(ref, strlen(ref), name, len)) {
+ return protocol_versions[u].version;
+ }
+ }
+}
+
+/* see brssl.h */
+unsigned
+parse_hash_functions(const char *arg)
+{
+ unsigned r;
+
+ r = 0;
+ for (;;) {
+ const char *name;
+ size_t len;
+ size_t u;
+
+ name = next_word(&arg, &len);
+ if (name == NULL) {
+ break;
+ }
+ for (u = 0;; u ++) {
+ const char *ref;
+
+ ref = hash_functions[u].name;
+ if (ref == 0) {
+ fprintf(stderr, "ERROR: unrecognised"
+ " hash function name: '");
+ fwrite(name, 1, len, stderr);
+ fprintf(stderr, "'\n");
+ return 0;
+ }
+ if (eqstr_chunk(ref, strlen(ref), name, len)) {
+ int id;
+
+ id = (hash_functions[u].hclass->desc
+ >> BR_HASHDESC_ID_OFF)
+ & BR_HASHDESC_ID_MASK;
+ r |= (unsigned)1 << id;
+ break;
+ }
+ }
+ }
+ if (r == 0) {
+ fprintf(stderr, "ERROR: no hash function name provided\n");
+ }
+ return r;
+}
+
+/* see brssl.h */
+cipher_suite *
+parse_suites(const char *arg, size_t *num)
+{
+ VECTOR(cipher_suite) suites = VEC_INIT;
+ cipher_suite *r;
+
+ for (;;) {
+ const char *name;
+ size_t u, len;
+
+ name = next_word(&arg, &len);
+ if (name == NULL) {
+ break;
+ }
+ for (u = 0;; u ++) {
+ const char *ref;
+
+ ref = cipher_suites[u].name;
+ if (ref == NULL) {
+ fprintf(stderr, "ERROR: unrecognised"
+ " cipher suite '");
+ fwrite(name, 1, len, stderr);
+ fprintf(stderr, "'\n");
+ return 0;
+ }
+ if (eqstr_chunk(ref, strlen(ref), name, len)) {
+ VEC_ADD(suites, cipher_suites[u]);
+ break;
+ }
+ }
+ }
+ if (VEC_LEN(suites) == 0) {
+ fprintf(stderr, "ERROR: no cipher suite provided\n");
+ }
+ r = VEC_TOARRAY(suites);
+ *num = VEC_LEN(suites);
+ VEC_CLEAR(suites);
+ return r;
+}
+
+/* see brssl.h */
+const char *
+ec_curve_name(int curve)
+{
+ switch (curve) {
+ case BR_EC_sect163k1: return "sect163k1";
+ case BR_EC_sect163r1: return "sect163r1";
+ case BR_EC_sect163r2: return "sect163r2";
+ case BR_EC_sect193r1: return "sect193r1";
+ case BR_EC_sect193r2: return "sect193r2";
+ case BR_EC_sect233k1: return "sect233k1";
+ case BR_EC_sect233r1: return "sect233r1";
+ case BR_EC_sect239k1: return "sect239k1";
+ case BR_EC_sect283k1: return "sect283k1";
+ case BR_EC_sect283r1: return "sect283r1";
+ case BR_EC_sect409k1: return "sect409k1";
+ case BR_EC_sect409r1: return "sect409r1";
+ case BR_EC_sect571k1: return "sect571k1";
+ case BR_EC_sect571r1: return "sect571r1";
+ case BR_EC_secp160k1: return "secp160k1";
+ case BR_EC_secp160r1: return "secp160r1";
+ case BR_EC_secp160r2: return "secp160r2";
+ case BR_EC_secp192k1: return "secp192k1";
+ case BR_EC_secp192r1: return "secp192r1";
+ case BR_EC_secp224k1: return "secp224k1";
+ case BR_EC_secp224r1: return "secp224r1";
+ case BR_EC_secp256k1: return "secp256k1";
+ case BR_EC_secp256r1: return "secp256r1";
+ case BR_EC_secp384r1: return "secp384r1";
+ case BR_EC_secp521r1: return "secp521r1";
+ case BR_EC_brainpoolP256r1: return "brainpoolP256r1";
+ case BR_EC_brainpoolP384r1: return "brainpoolP384r1";
+ case BR_EC_brainpoolP512r1: return "brainpoolP512r1";
+ default:
+ return "unknown";
+ }
+}
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/poll.h>
+
+#include "brssl.h"
+#include "bearssl.h"
+
+static int
+host_bind(const char *host, const char *port, int verbose)
+{
+ struct addrinfo hints, *si, *p;
+ int fd;
+ int err;
+
+ memset(&hints, 0, sizeof hints);
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ err = getaddrinfo(host, port, &hints, &si);
+ if (err != 0) {
+ fprintf(stderr, "ERROR: getaddrinfo(): %s\n",
+ gai_strerror(err));
+ return -1;
+ }
+ fd = -1;
+ for (p = si; p != NULL; p = p->ai_next) {
+ struct sockaddr *sa;
+ struct sockaddr_in sa4;
+ struct sockaddr_in6 sa6;
+ size_t sa_len;
+ void *addr;
+ char tmp[INET6_ADDRSTRLEN + 50];
+ int opt;
+
+ sa = (struct sockaddr *)p->ai_addr;
+ if (sa->sa_family == AF_INET) {
+ sa4 = *(struct sockaddr_in *)sa;
+ sa = (struct sockaddr *)&sa4;
+ sa_len = sizeof sa4;
+ addr = &sa4.sin_addr;
+ if (host == NULL) {
+ sa4.sin_addr.s_addr = INADDR_ANY;
+ }
+ } else if (sa->sa_family == AF_INET6) {
+ sa6 = *(struct sockaddr_in6 *)sa;
+ sa = (struct sockaddr *)&sa6;
+ sa_len = sizeof sa6;
+ addr = &sa6.sin6_addr;
+ if (host == NULL) {
+ sa6.sin6_addr = in6addr_any;
+ }
+ } else {
+ addr = NULL;
+ sa_len = p->ai_addrlen;
+ }
+ if (addr != NULL) {
+ inet_ntop(p->ai_family, addr, tmp, sizeof tmp);
+ } else {
+ sprintf(tmp, "<unknown family: %d>",
+ (int)sa->sa_family);
+ }
+ if (verbose) {
+ fprintf(stderr, "binding to: %s\n", tmp);
+ }
+ fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
+ if (fd < 0) {
+ if (verbose) {
+ perror("socket()");
+ }
+ continue;
+ }
+ opt = 1;
+ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof opt);
+ opt = 0;
+ setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof opt);
+ if (bind(fd, sa, sa_len) < 0) {
+ if (verbose) {
+ perror("bind()");
+ }
+ close(fd);
+ continue;
+ }
+ break;
+ }
+ if (p == NULL) {
+ freeaddrinfo(si);
+ fprintf(stderr, "ERROR: failed to bind\n");
+ return -1;
+ }
+ freeaddrinfo(si);
+ if (listen(fd, 5) < 0) {
+ if (verbose) {
+ perror("listen()");
+ }
+ close(fd);
+ return -1;
+ }
+ if (verbose) {
+ fprintf(stderr, "bound.\n");
+ }
+ return fd;
+}
+
+static int
+accept_client(int server_fd, int verbose)
+{
+ int fd;
+ struct sockaddr sa;
+ socklen_t sa_len;
+
+ sa_len = sizeof sa;
+ fd = accept(server_fd, &sa, &sa_len);
+ if (fd < 0) {
+ if (verbose) {
+ perror("accept()");
+ }
+ return -1;
+ }
+ if (verbose) {
+ char tmp[INET6_ADDRSTRLEN + 50];
+ const char *name;
+
+ name = NULL;
+ switch (sa.sa_family) {
+ case AF_INET:
+ name = inet_ntop(AF_INET,
+ &((struct sockaddr_in *)&sa)->sin_addr,
+ tmp, sizeof tmp);
+ break;
+ case AF_INET6:
+ name = inet_ntop(AF_INET,
+ &((struct sockaddr_in *)&sa)->sin_addr,
+ tmp, sizeof tmp);
+ break;
+ }
+ if (name == NULL) {
+ sprintf(tmp, "<unknown: %lu>",
+ (unsigned long)sa.sa_family);
+ name = tmp;
+ }
+ fprintf(stderr, "accepting connection from: %s\n", name);
+ }
+
+ /*
+ * We make the socket non-blocking, since we are going to use
+ * poll() to organise I/O.
+ */
+ fcntl(fd, F_SETFL, O_NONBLOCK);
+ return fd;
+}
+
+static void
+usage_server(void)
+{
+ fprintf(stderr,
+"usage: brssl server [ options ]\n");
+ fprintf(stderr,
+"options:\n");
+ fprintf(stderr,
+" -q suppress verbose messages\n");
+ fprintf(stderr,
+" -trace activate extra debug messages (dump of all packets)\n");
+ fprintf(stderr,
+" -b name bind to a specific address or host name\n");
+ fprintf(stderr,
+" -p port bind to a specific port (default: 4433)\n");
+ fprintf(stderr,
+" -mono use monodirectional buffering\n");
+ fprintf(stderr,
+" -buf length set the I/O buffer length (in bytes)\n");
+ fprintf(stderr,
+" -cache length set the session cache storage length (in bytes)\n");
+ fprintf(stderr,
+" -cert fname read certificate chain from file 'fname'\n");
+ fprintf(stderr,
+" -key fname read private key from file 'fname'\n");
+ fprintf(stderr,
+" -list list supported names (protocols, algorithms...)\n");
+ fprintf(stderr,
+" -vmin name set minimum supported version (default: TLS-1.0)\n");
+ fprintf(stderr,
+" -vmax name set maximum supported version (default: TLS-1.2)\n");
+ fprintf(stderr,
+" -cs names set list of supported cipher suites (comma-separated)\n");
+ fprintf(stderr,
+" -hf names add support for some hash functions (comma-separated)\n");
+ fprintf(stderr,
+" -serverpref enforce server's preferences for cipher suites\n");
+ exit(EXIT_FAILURE);
+}
+
+typedef struct {
+ const br_ssl_server_policy_class *vtable;
+ int verbose;
+ br_x509_certificate *chain;
+ size_t chain_len;
+ int cert_signer_algo;
+ private_key *sk;
+} policy_context;
+
+static int
+get_cert_signer_algo(br_x509_certificate *xc)
+{
+ br_x509_decoder_context dc;
+ int err;
+
+ br_x509_decoder_init(&dc, 0, 0);
+ br_x509_decoder_push(&dc, xc->data, xc->data_len);
+ err = br_x509_decoder_last_error(&dc);
+ if (err != 0) {
+ return -err;
+ } else {
+ return br_x509_decoder_get_signer_key_type(&dc);
+ }
+}
+
+static int
+sp_choose(const br_ssl_server_policy_class **pctx,
+ const br_ssl_server_context *cc,
+ br_ssl_server_choices *choices)
+{
+ policy_context *pc;
+ const br_suite_translated *st;
+ size_t u, st_num;
+ unsigned chashes;
+ int hash_id;
+
+ pc = (policy_context *)pctx;
+ st = br_ssl_server_get_client_suites(cc, &st_num);
+ chashes = br_ssl_server_get_client_hashes(cc);
+ for (hash_id = 6; hash_id >= 2; hash_id --) {
+ if ((chashes >> hash_id) & 1) {
+ break;
+ }
+ }
+ if (pc->verbose) {
+ fprintf(stderr, "Client parameters:\n");
+ fprintf(stderr, " Maximum version: ");
+ switch (cc->client_max_version) {
+ case BR_SSL30:
+ fprintf(stderr, "SSL 3.0");
+ break;
+ case BR_TLS10:
+ fprintf(stderr, "TLS 1.0");
+ break;
+ case BR_TLS11:
+ fprintf(stderr, "TLS 1.1");
+ break;
+ case BR_TLS12:
+ fprintf(stderr, "TLS 1.2");
+ break;
+ default:
+ fprintf(stderr, "unknown (0x%04X)",
+ (unsigned)cc->client_max_version);
+ break;
+ }
+ fprintf(stderr, "\n");
+ fprintf(stderr, " Compatible cipher suites:\n");
+ for (u = 0; u < st_num; u ++) {
+ char csn[80];
+
+ get_suite_name_ext(st[u][0], csn, sizeof csn);
+ fprintf(stderr, " %s\n", csn);
+ }
+ fprintf(stderr, " Common hash functions:");
+ for (u = 2; u <= 6; u ++) {
+ if ((chashes >> u) & 1) {
+ int z;
+
+ switch (u) {
+ case 3: z = 224; break;
+ case 4: z = 256; break;
+ case 5: z = 384; break;
+ case 6: z = 512; break;
+ default:
+ z = 1;
+ break;
+ }
+ fprintf(stderr, " sha%d", z);
+ }
+ }
+ fprintf(stderr, "\n");
+ }
+ for (u = 0; u < st_num; u ++) {
+ unsigned tt;
+
+ tt = st[u][1];
+ switch (tt >> 12) {
+ case BR_SSLKEYX_RSA:
+ if (pc->sk->key_type == BR_KEYTYPE_RSA) {
+ choices->cipher_suite = st[u][0];
+ goto choose_ok;
+ }
+ break;
+ case BR_SSLKEYX_ECDHE_RSA:
+ if (pc->sk->key_type == BR_KEYTYPE_RSA) {
+ choices->cipher_suite = st[u][0];
+ choices->hash_id = hash_id;
+ goto choose_ok;
+ }
+ break;
+ case BR_SSLKEYX_ECDHE_ECDSA:
+ if (pc->sk->key_type == BR_KEYTYPE_EC) {
+ choices->cipher_suite = st[u][0];
+ choices->hash_id = hash_id;
+ goto choose_ok;
+ }
+ break;
+ case BR_SSLKEYX_ECDH_RSA:
+ if (pc->sk->key_type == BR_KEYTYPE_EC
+ && pc->cert_signer_algo == BR_KEYTYPE_RSA)
+ {
+ choices->cipher_suite = st[u][0];
+ goto choose_ok;
+ }
+ break;
+ case BR_SSLKEYX_ECDH_ECDSA:
+ if (pc->sk->key_type == BR_KEYTYPE_EC
+ && pc->cert_signer_algo == BR_KEYTYPE_EC)
+ {
+ choices->cipher_suite = st[u][0];
+ goto choose_ok;
+ }
+ break;
+ }
+ }
+ return 0;
+
+choose_ok:
+ choices->chain = pc->chain;
+ choices->chain_len = pc->chain_len;
+ if (pc->verbose) {
+ char csn[80];
+
+ get_suite_name_ext(choices->cipher_suite, csn, sizeof csn);
+ fprintf(stderr, "Using: %s\n", csn);
+ }
+ return 1;
+}
+
+static uint32_t
+sp_do_keyx(const br_ssl_server_policy_class **pctx,
+ unsigned char *data, size_t len)
+{
+ policy_context *pc;
+
+ pc = (policy_context *)pctx;
+ switch (pc->sk->key_type) {
+ case BR_KEYTYPE_RSA:
+ return br_rsa_ssl_decrypt(
+ &br_rsa_i31_private, &pc->sk->key.rsa,
+ data, len);
+ case BR_KEYTYPE_EC:
+ return br_ec_prime_i31.mul(data, len, pc->sk->key.ec.x,
+ pc->sk->key.ec.xlen, pc->sk->key.ec.curve);
+ default:
+ fprintf(stderr, "ERROR: unknown private key type (%d)\n",
+ (int)pc->sk->key_type);
+ return 0;
+ }
+}
+
+/*
+ * OID for hash functions in RSA signatures.
+ */
+static const unsigned char HASH_OID_SHA1[] = {
+ 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A
+};
+
+static const unsigned char HASH_OID_SHA224[] = {
+ 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04
+};
+
+static const unsigned char HASH_OID_SHA256[] = {
+ 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01
+};
+
+static const unsigned char HASH_OID_SHA384[] = {
+ 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02
+};
+
+static const unsigned char HASH_OID_SHA512[] = {
+ 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03
+};
+
+static const unsigned char *HASH_OID[] = {
+ HASH_OID_SHA1,
+ HASH_OID_SHA224,
+ HASH_OID_SHA256,
+ HASH_OID_SHA384,
+ HASH_OID_SHA512
+};
+
+static const br_hash_class *
+get_hash_impl(int hash_id)
+{
+ size_t u;
+
+ for (u = 0; hash_functions[u].name; u ++) {
+ const br_hash_class *hc;
+ int id;
+
+ hc = hash_functions[u].hclass;
+ id = (hc->desc >> BR_HASHDESC_ID_OFF) & BR_HASHDESC_ID_MASK;
+ if (id == hash_id) {
+ return hc;
+ }
+ }
+ return NULL;
+}
+
+static size_t
+sp_do_sign(const br_ssl_server_policy_class **pctx,
+ int hash_id, size_t hv_len, unsigned char *data, size_t len)
+{
+ policy_context *pc;
+ unsigned char hv[64];
+
+ pc = (policy_context *)pctx;
+ memcpy(hv, data, hv_len);
+ switch (pc->sk->key_type) {
+ size_t sig_len;
+ uint32_t x;
+ const unsigned char *hash_oid;
+ const br_hash_class *hc;
+
+ case BR_KEYTYPE_RSA:
+ if (hash_id == 0) {
+ hash_oid = NULL;
+ } else if (hash_id >= 2 && hash_id <= 6) {
+ hash_oid = HASH_OID[hash_id - 2];
+ } else {
+ if (pc->verbose) {
+ fprintf(stderr, "ERROR: cannot RSA-sign with"
+ " unknown hash function: %d\n",
+ hash_id);
+ }
+ return 0;
+ }
+ sig_len = (pc->sk->key.rsa.n_bitlen + 7) >> 3;
+ if (len < sig_len) {
+ if (pc->verbose) {
+ fprintf(stderr, "ERROR: cannot RSA-sign,"
+ " buffer is too small"
+ " (sig=%lu, buf=%lu)\n",
+ (unsigned long)sig_len,
+ (unsigned long)len);
+ }
+ return 0;
+ }
+ x = br_rsa_i31_pkcs1_sign(hash_oid, hv, hv_len,
+ &pc->sk->key.rsa, data);
+ if (!x) {
+ if (pc->verbose) {
+ fprintf(stderr, "ERROR: RSA-sign failure\n");
+ }
+ return 0;
+ }
+ return sig_len;
+
+ case BR_KEYTYPE_EC:
+ hc = get_hash_impl(hash_id);
+ if (hc == NULL) {
+ if (pc->verbose) {
+ fprintf(stderr, "ERROR: cannot RSA-sign with"
+ " unknown hash function: %d\n",
+ hash_id);
+ }
+ return 0;
+ }
+ if (len < 139) {
+ if (pc->verbose) {
+ fprintf(stderr, "ERROR: cannot ECDSA-sign"
+ " (output buffer = %lu)\n",
+ (unsigned long)len);
+ }
+ return 0;
+ }
+ sig_len = br_ecdsa_i31_sign_asn1(&br_ec_prime_i31,
+ hc, hv, &pc->sk->key.ec, data);
+ if (sig_len == 0) {
+ if (pc->verbose) {
+ fprintf(stderr, "ERROR: ECDSA-sign failure\n");
+ }
+ return 0;
+ }
+ return sig_len;
+
+ default:
+ return 0;
+ }
+}
+
+static const br_ssl_server_policy_class policy_vtable = {
+ sizeof(policy_context),
+ sp_choose,
+ sp_do_keyx,
+ sp_do_sign
+};
+
+/* see brssl.h */
+int
+do_server(int argc, char *argv[])
+{
+ int retcode;
+ int verbose;
+ int trace;
+ int i, bidi;
+ const char *bind_name;
+ const char *port;
+ unsigned vmin, vmax;
+ cipher_suite *suites;
+ size_t num_suites;
+ uint16_t *suite_ids;
+ unsigned hfuns;
+ br_x509_certificate *chain;
+ size_t chain_len;
+ int cert_signer_algo;
+ private_key *sk;
+ size_t u;
+ br_ssl_server_context cc;
+ policy_context pc;
+ br_ssl_session_cache_lru lru;
+ unsigned char *iobuf, *cache;
+ size_t iobuf_len, cache_len;
+ uint32_t flags;
+ int server_fd, fd;
+
+ retcode = 0;
+ verbose = 1;
+ trace = 0;
+ bind_name = NULL;
+ port = NULL;
+ bidi = 1;
+ vmin = 0;
+ vmax = 0;
+ suites = NULL;
+ num_suites = 0;
+ hfuns = 0;
+ suite_ids = NULL;
+ chain = NULL;
+ chain_len = 0;
+ sk = NULL;
+ iobuf = NULL;
+ iobuf_len = 0;
+ cache = NULL;
+ cache_len = (size_t)-1;
+ flags = 0;
+ server_fd = -1;
+ fd = -1;
+ for (i = 0; i < argc; i ++) {
+ const char *arg;
+
+ arg = argv[i];
+ if (arg[0] != '-') {
+ usage_server();
+ goto server_exit_error;
+ }
+ if (eqstr(arg, "-v") || eqstr(arg, "-verbose")) {
+ verbose = 1;
+ } else if (eqstr(arg, "-q") || eqstr(arg, "-quiet")) {
+ verbose = 0;
+ } else if (eqstr(arg, "-trace")) {
+ trace = 1;
+ } else if (eqstr(arg, "-b")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-b'\n");
+ usage_server();
+ goto server_exit_error;
+ }
+ if (bind_name != NULL) {
+ fprintf(stderr, "ERROR: duplicate bind host\n");
+ usage_server();
+ goto server_exit_error;
+ }
+ bind_name = argv[i];
+ } else if (eqstr(arg, "-p")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-p'\n");
+ usage_server();
+ goto server_exit_error;
+ }
+ if (port != NULL) {
+ fprintf(stderr, "ERROR: duplicate bind port\n");
+ usage_server();
+ goto server_exit_error;
+ }
+ port = argv[i];
+ } else if (eqstr(arg, "-mono")) {
+ bidi = 0;
+ } else if (eqstr(arg, "-buf")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-buf'\n");
+ usage_server();
+ goto server_exit_error;
+ }
+ arg = argv[i];
+ if (iobuf_len != 0) {
+ fprintf(stderr,
+ "ERROR: duplicate I/O buffer length\n");
+ usage_server();
+ goto server_exit_error;
+ }
+ iobuf_len = strtoul(arg, 0, 10);
+ } else if (eqstr(arg, "-cache")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-cache'\n");
+ usage_server();
+ goto server_exit_error;
+ }
+ arg = argv[i];
+ if (cache_len != (size_t)-1) {
+ fprintf(stderr, "ERROR: duplicate session"
+ " cache length\n");
+ usage_server();
+ goto server_exit_error;
+ }
+ cache_len = strtoul(arg, 0, 10);
+ } else if (eqstr(arg, "-cert")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-cert'\n");
+ usage_server();
+ goto server_exit_error;
+ }
+ if (chain != NULL) {
+ fprintf(stderr,
+ "ERROR: duplicate certificate chain\n");
+ usage_server();
+ goto server_exit_error;
+ }
+ arg = argv[i];
+ chain = read_certificates(arg, &chain_len);
+ if (chain == NULL || chain_len == 0) {
+ goto server_exit_error;
+ }
+ } else if (eqstr(arg, "-key")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-key'\n");
+ usage_server();
+ goto server_exit_error;
+ }
+ if (sk != NULL) {
+ fprintf(stderr,
+ "ERROR: duplicate private key\n");
+ usage_server();
+ goto server_exit_error;
+ }
+ arg = argv[i];
+ sk = read_private_key(arg);
+ if (sk == NULL) {
+ goto server_exit_error;
+ }
+ } else if (eqstr(arg, "-list")) {
+ list_names();
+ goto server_exit;
+ } else if (eqstr(arg, "-vmin")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-vmin'\n");
+ usage_server();
+ goto server_exit_error;
+ }
+ arg = argv[i];
+ if (vmin != 0) {
+ fprintf(stderr,
+ "ERROR: duplicate minimum version\n");
+ usage_server();
+ goto server_exit_error;
+ }
+ vmin = parse_version(arg, strlen(arg));
+ if (vmin == 0) {
+ fprintf(stderr,
+ "ERROR: unrecognised version '%s'\n",
+ arg);
+ usage_server();
+ goto server_exit_error;
+ }
+ } else if (eqstr(arg, "-vmax")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-vmax'\n");
+ usage_server();
+ goto server_exit_error;
+ }
+ arg = argv[i];
+ if (vmax != 0) {
+ fprintf(stderr,
+ "ERROR: duplicate maximum version\n");
+ usage_server();
+ goto server_exit_error;
+ }
+ vmax = parse_version(arg, strlen(arg));
+ if (vmax == 0) {
+ fprintf(stderr,
+ "ERROR: unrecognised version '%s'\n",
+ arg);
+ usage_server();
+ goto server_exit_error;
+ }
+ } else if (eqstr(arg, "-cs")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-cs'\n");
+ usage_server();
+ goto server_exit_error;
+ }
+ arg = argv[i];
+ if (suites != NULL) {
+ fprintf(stderr, "ERROR: duplicate list"
+ " of cipher suites\n");
+ usage_server();
+ goto server_exit_error;
+ }
+ suites = parse_suites(arg, &num_suites);
+ if (suites == NULL) {
+ usage_server();
+ goto server_exit_error;
+ }
+ } else if (eqstr(arg, "-hf")) {
+ unsigned x;
+
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-hf'\n");
+ usage_server();
+ goto server_exit_error;
+ }
+ arg = argv[i];
+ x = parse_hash_functions(arg);
+ if (x == 0) {
+ usage_server();
+ goto server_exit_error;
+ }
+ hfuns |= x;
+ } else if (eqstr(arg, "-serverpref")) {
+ flags |= BR_OPT_ENFORCE_SERVER_PREFERENCES;
+ } else {
+ fprintf(stderr, "ERROR: unknown option: '%s'\n", arg);
+ usage_server();
+ goto server_exit_error;
+ }
+ }
+ if (port == NULL) {
+ port = "4433";
+ }
+ if (vmin == 0) {
+ vmin = BR_TLS10;
+ }
+ if (vmax == 0) {
+ vmax = BR_TLS12;
+ }
+ if (vmax < vmin) {
+ fprintf(stderr, "ERROR: impossible minimum/maximum protocol"
+ " version combination\n");
+ usage_server();
+ goto server_exit_error;
+ }
+ if (suites == NULL) {
+ num_suites = 0;
+
+ for (u = 0; cipher_suites[u].name; u ++) {
+ if ((cipher_suites[u].req & REQ_TLS12) == 0
+ || vmax >= BR_TLS12)
+ {
+ num_suites ++;
+ }
+ }
+ suites = xmalloc(num_suites * sizeof *suites);
+ num_suites = 0;
+ for (u = 0; cipher_suites[u].name; u ++) {
+ if ((cipher_suites[u].req & REQ_TLS12) == 0
+ || vmax >= BR_TLS12)
+ {
+ suites[num_suites ++] = cipher_suites[u];
+ }
+ }
+ }
+ if (hfuns == 0) {
+ hfuns = (unsigned)-1;
+ }
+ if (chain == NULL || chain_len == 0) {
+ fprintf(stderr, "ERROR: no certificate chain provided\n");
+ goto server_exit_error;
+ }
+ if (sk == NULL) {
+ fprintf(stderr, "ERROR: no private key provided\n");
+ goto server_exit_error;
+ }
+ switch (sk->key_type) {
+ int curve;
+ uint32_t supp;
+
+ case BR_KEYTYPE_RSA:
+ break;
+ case BR_KEYTYPE_EC:
+ curve = sk->key.ec.curve;
+ supp = br_ec_prime_i31.supported_curves;
+ if (curve > 31 || !((supp >> curve) & 1)) {
+ fprintf(stderr, "ERROR: private key curve (%d)"
+ " is not supported\n", curve);
+ goto server_exit_error;
+ }
+ break;
+ default:
+ fprintf(stderr, "ERROR: unsupported private key type (%d)\n",
+ sk->key_type);
+ break;
+ }
+ cert_signer_algo = get_cert_signer_algo(chain);
+ if (cert_signer_algo < 0) {
+ fprintf(stderr, "ERROR: server certificate cannot be"
+ " decoded (err=%d)\n", -cert_signer_algo);
+ goto server_exit_error;
+ } else if (verbose) {
+ const char *csas;
+
+ switch (cert_signer_algo) {
+ case BR_KEYTYPE_RSA: csas = "RSA"; break;
+ case BR_KEYTYPE_EC: csas = "EC"; break;
+ default:
+ csas = "unknown";
+ break;
+ }
+ fprintf(stderr, "Issuing CA key type: %d (%s)\n",
+ cert_signer_algo, csas);
+ }
+ if (iobuf_len == 0) {
+ if (bidi) {
+ iobuf_len = BR_SSL_BUFSIZE_BIDI;
+ } else {
+ iobuf_len = BR_SSL_BUFSIZE_MONO;
+ }
+ }
+ iobuf = xmalloc(iobuf_len);
+ if (cache_len == (size_t)-1) {
+ cache_len = 5000;
+ }
+ cache = xmalloc(cache_len);
+
+ /*
+ * Compute implementation requirements and inject implementations.
+ */
+ suite_ids = xmalloc(num_suites * sizeof *suite_ids);
+ br_ssl_server_zero(&cc);
+ br_ssl_engine_set_versions(&cc.eng, vmin, vmax);
+ br_ssl_server_set_all_flags(&cc, flags);
+ if (vmin <= BR_TLS11) {
+ if (!(hfuns & (1 << br_md5_ID))) {
+ fprintf(stderr, "ERROR: TLS 1.0 and 1.1 need MD5\n");
+ goto server_exit_error;
+ }
+ if (!(hfuns & (1 << br_sha1_ID))) {
+ fprintf(stderr, "ERROR: TLS 1.0 and 1.1 need SHA-1\n");
+ goto server_exit_error;
+ }
+ }
+ for (u = 0; u < num_suites; u ++) {
+ unsigned req;
+
+ req = suites[u].req;
+ suite_ids[u] = suites[u].suite;
+ if ((req & REQ_TLS12) != 0 && vmax < BR_TLS12) {
+ fprintf(stderr,
+ "ERROR: cipher suite %s requires TLS 1.2\n",
+ suites[u].name);
+ goto server_exit_error;
+ }
+ if ((req & REQ_SHA1) != 0 && !(hfuns & (1 << br_sha1_ID))) {
+ fprintf(stderr,
+ "ERROR: cipher suite %s requires SHA-1\n",
+ suites[u].name);
+ goto server_exit_error;
+ }
+ if ((req & REQ_SHA256) != 0 && !(hfuns & (1 << br_sha256_ID))) {
+ fprintf(stderr,
+ "ERROR: cipher suite %s requires SHA-256\n",
+ suites[u].name);
+ goto server_exit_error;
+ }
+ if ((req & REQ_SHA384) != 0 && !(hfuns & (1 << br_sha384_ID))) {
+ fprintf(stderr,
+ "ERROR: cipher suite %s requires SHA-384\n",
+ suites[u].name);
+ goto server_exit_error;
+ }
+ /* TODO: algorithm implementation selection */
+ if ((req & REQ_AESCBC) != 0) {
+ br_ssl_engine_set_aes_cbc(&cc.eng,
+ &br_aes_ct_cbcenc_vtable,
+ &br_aes_ct_cbcdec_vtable);
+ br_ssl_engine_set_cbc(&cc.eng,
+ &br_sslrec_in_cbc_vtable,
+ &br_sslrec_out_cbc_vtable);
+ }
+ if ((req & REQ_AESGCM) != 0) {
+ br_ssl_engine_set_aes_ctr(&cc.eng,
+ &br_aes_ct_ctr_vtable);
+ br_ssl_engine_set_ghash(&cc.eng,
+ &br_ghash_ctmul);
+ br_ssl_engine_set_gcm(&cc.eng,
+ &br_sslrec_in_gcm_vtable,
+ &br_sslrec_out_gcm_vtable);
+ }
+ if ((req & REQ_3DESCBC) != 0) {
+ br_ssl_engine_set_des_cbc(&cc.eng,
+ &br_des_ct_cbcenc_vtable,
+ &br_des_ct_cbcdec_vtable);
+ br_ssl_engine_set_cbc(&cc.eng,
+ &br_sslrec_in_cbc_vtable,
+ &br_sslrec_out_cbc_vtable);
+ }
+ if ((req & (REQ_ECDHE_RSA | REQ_ECDHE_ECDSA)) != 0) {
+ br_ssl_engine_set_ec(&cc.eng, &br_ec_prime_i31);
+ }
+ }
+ br_ssl_engine_set_suites(&cc.eng, suite_ids, num_suites);
+
+ for (u = 0; hash_functions[u].name; u ++) {
+ const br_hash_class *hc;
+ int id;
+
+ hc = hash_functions[u].hclass;
+ id = (hc->desc >> BR_HASHDESC_ID_OFF) & BR_HASHDESC_ID_MASK;
+ if ((hfuns & ((unsigned)1 << id)) != 0) {
+ br_ssl_engine_set_hash(&cc.eng, id, hc);
+ }
+ }
+ if (vmin <= BR_TLS11) {
+ br_ssl_engine_set_prf10(&cc.eng, &br_tls10_prf);
+ }
+ if (vmax >= BR_TLS12) {
+ if ((hfuns & ((unsigned)1 << br_sha256_ID)) != 0) {
+ br_ssl_engine_set_prf_sha256(&cc.eng,
+ &br_tls12_sha256_prf);
+ }
+ if ((hfuns & ((unsigned)1 << br_sha384_ID)) != 0) {
+ br_ssl_engine_set_prf_sha384(&cc.eng,
+ &br_tls12_sha384_prf);
+ }
+ }
+
+ br_ssl_session_cache_lru_init(&lru, cache, cache_len);
+ br_ssl_server_set_cache(&cc, &lru.vtable);
+
+ pc.vtable = &policy_vtable;
+ pc.verbose = verbose;
+ pc.chain = chain;
+ pc.chain_len = chain_len;
+ pc.cert_signer_algo = cert_signer_algo;
+ pc.sk = sk;
+ br_ssl_server_set_policy(&cc, &pc.vtable);
+
+ br_ssl_engine_set_buffer(&cc.eng, iobuf, iobuf_len, bidi);
+
+ /*
+ * Open the server socket.
+ */
+ server_fd = host_bind(bind_name, port, verbose);
+ if (server_fd < 0) {
+ goto server_exit_error;
+ }
+
+ /*
+ * Process incoming clients, one at a time. Note that we do not
+ * accept any client until the previous connection has finished:
+ * this is voluntary, since the tool uses stdin/stdout for
+ * application data, and thus cannot really run two connections
+ * simultaneously.
+ */
+ for (;;) {
+ int x;
+
+ fd = accept_client(server_fd, verbose);
+ if (fd < 0) {
+ goto server_exit_error;
+ }
+ br_ssl_server_reset(&cc);
+ x = run_ssl_engine(&cc.eng, fd,
+ (verbose ? RUN_ENGINE_VERBOSE : 0)
+ | (trace ? RUN_ENGINE_TRACE : 0));
+ close(fd);
+ fd = -1;
+ if (x < -1) {
+ goto server_exit_error;
+ }
+ }
+
+ /*
+ * Release allocated structures.
+ */
+server_exit:
+ xfree(suites);
+ xfree(suite_ids);
+ if (chain != NULL) {
+ for (u = 0; u < chain_len; u ++) {
+ xfree(chain[u].data);
+ }
+ xfree(chain);
+ }
+ if (sk != NULL) {
+ free_private_key(sk);
+ }
+ xfree(iobuf);
+ xfree(cache);
+ if (fd >= 0) {
+ close(fd);
+ }
+ return retcode;
+
+server_exit_error:
+ retcode = -1;
+ goto server_exit;
+}
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include "brssl.h"
+#include "bearssl.h"
+
+static void
+print_int_text(const char *name, const unsigned char *buf, size_t len)
+{
+ size_t u;
+
+ printf("%s = ", name);
+ for (u = 0; u < len; u ++) {
+ printf("%02X", buf[u]);
+ }
+ printf("\n");
+}
+
+static void
+print_int_C(const char *name, const unsigned char *buf, size_t len)
+{
+ size_t u;
+
+ printf("\nstatic const unsigned char %s[] = {", name);
+ for (u = 0; u < len; u ++) {
+ if (u != 0) {
+ printf(",");
+ }
+ if (u % 12 == 0) {
+ printf("\n\t");
+ } else {
+ printf(" ");
+ }
+ printf("0x%02X", buf[u]);
+ }
+ printf("\n};\n");
+}
+
+static void
+print_rsa(const br_rsa_private_key *sk, int print_text, int print_C)
+{
+ if (print_text) {
+ print_int_text("p ", sk->p, sk->plen);
+ print_int_text("q ", sk->q, sk->qlen);
+ print_int_text("dp", sk->dp, sk->dplen);
+ print_int_text("dq", sk->dq, sk->dqlen);
+ print_int_text("iq", sk->iq, sk->iqlen);
+ }
+ if (print_C) {
+ print_int_C("RSA_P", sk->p, sk->plen);
+ print_int_C("RSA_Q", sk->q, sk->qlen);
+ print_int_C("RSA_DP", sk->dp, sk->dplen);
+ print_int_C("RSA_DQ", sk->dq, sk->dqlen);
+ print_int_C("RSA_IQ", sk->iq, sk->iqlen);
+ printf("\nstatic const br_rsa_private_key RSA = {\n");
+ printf("\t%lu,\n", (unsigned long)sk->n_bitlen);
+ printf("\t(unsigned char *)RSA_P, sizeof RSA_P,\n");
+ printf("\t(unsigned char *)RSA_Q, sizeof RSA_Q,\n");
+ printf("\t(unsigned char *)RSA_DP, sizeof RSA_DP,\n");
+ printf("\t(unsigned char *)RSA_DQ, sizeof RSA_DQ,\n");
+ printf("\t(unsigned char *)RSA_IQ, sizeof RSA_IQ\n");
+ printf("};\n");
+ }
+}
+
+static void
+print_ec(const br_ec_private_key *sk, int print_text, int print_C)
+{
+ if (print_text) {
+ print_int_text("x", sk->x, sk->xlen);
+ }
+ if (print_C) {
+ print_int_C("EC_X", sk->x, sk->xlen);
+ printf("\nstatic const br_ec_private_key EC = {\n");
+ printf("\t%d,\n", sk->curve);
+ printf("\t(unsigned char *)EC_X, sizeof EC_X\n");
+ printf("};\n");
+ }
+}
+
+static int
+decode_key(const unsigned char *buf, size_t len, int print_text, int print_C)
+{
+ br_skey_decoder_context dc;
+ int err;
+
+ br_skey_decoder_init(&dc);
+ br_skey_decoder_push(&dc, buf, len);
+ err = br_skey_decoder_last_error(&dc);
+ if (err != 0) {
+ const char *errname, *errmsg;
+
+ fprintf(stderr, "ERROR (decoding): err=%d\n", err);
+ errname = find_error_name(err, &errmsg);
+ if (errname != NULL) {
+ fprintf(stderr, " %s: %s\n", errname, errmsg);
+ } else {
+ fprintf(stderr, " (unknown)\n");
+ }
+ return -1;
+ }
+ switch (br_skey_decoder_key_type(&dc)) {
+ const br_rsa_private_key *rk;
+ const br_ec_private_key *ek;
+
+ case BR_KEYTYPE_RSA:
+ rk = br_skey_decoder_get_rsa(&dc);
+ printf("RSA key (%lu bits)\n", (unsigned long)rk->n_bitlen);
+ print_rsa(rk, print_text, print_C);
+ break;
+
+ case BR_KEYTYPE_EC:
+ ek = br_skey_decoder_get_ec(&dc);
+ printf("EC key (curve = %d: %s)\n",
+ ek->curve, ec_curve_name(ek->curve));
+ print_ec(ek, print_text, print_C);
+ break;
+
+ default:
+ fprintf(stderr, "Unknown key type: %d\n",
+ br_skey_decoder_key_type(&dc));
+ return -1;
+ }
+
+ return 0;
+}
+
+static void
+usage_skey(void)
+{
+ fprintf(stderr,
+"usage: brssl skey [ options ] file...\n");
+ fprintf(stderr,
+"options:\n");
+ fprintf(stderr,
+" -q suppress verbose messages\n");
+ fprintf(stderr,
+" -text print public key details (human-readable)\n");
+ fprintf(stderr,
+" -C print public key details (C code)\n");
+}
+
+/* see brssl.h */
+int
+do_skey(int argc, char *argv[])
+{
+ int retcode;
+ int verbose;
+ int i, num_files;
+ int print_text, print_C;
+ unsigned char *buf;
+ size_t len;
+ pem_object *pos;
+
+ retcode = 0;
+ verbose = 1;
+ print_text = 0;
+ print_C = 0;
+ num_files = 0;
+ buf = NULL;
+ pos = NULL;
+ for (i = 0; i < argc; i ++) {
+ const char *arg;
+
+ arg = argv[i];
+ if (arg[0] != '-') {
+ num_files ++;
+ continue;
+ }
+ argv[i] = NULL;
+ if (eqstr(arg, "-v") || eqstr(arg, "-verbose")) {
+ verbose = 1;
+ } else if (eqstr(arg, "-q") || eqstr(arg, "-quiet")) {
+ verbose = 0;
+ } else if (eqstr(arg, "-text")) {
+ print_text = 1;
+ } else if (eqstr(arg, "-C")) {
+ print_C = 1;
+ } else {
+ fprintf(stderr, "ERROR: unknown option: '%s'\n", arg);
+ usage_skey();
+ goto skey_exit_error;
+ }
+ }
+ if (num_files == 0) {
+ fprintf(stderr, "ERROR: no private key provided\n");
+ usage_skey();
+ goto skey_exit_error;
+ }
+
+ for (i = 0; i < argc; i ++) {
+ const char *fname;
+
+ fname = argv[i];
+ if (fname == NULL) {
+ continue;
+ }
+ buf = read_file(fname, &len);
+ if (buf == NULL) {
+ goto skey_exit_error;
+ }
+ if (looks_like_DER(buf, len)) {
+ if (verbose) {
+ fprintf(stderr, "File '%s': ASN.1/DER object\n",
+ fname);
+ }
+ if (decode_key(buf, len, print_text, print_C) < 0) {
+ goto skey_exit_error;
+ }
+ } else {
+ size_t u, num;
+
+ if (verbose) {
+ fprintf(stderr, "File '%s': decoding as PEM\n",
+ fname);
+ }
+ pos = decode_pem(buf, len, &num);
+ if (pos == NULL) {
+ goto skey_exit_error;
+ }
+ for (u = 0; pos[u].name; u ++) {
+ const char *name;
+
+ name = pos[u].name;
+ if (eqstr(name, "RSA PRIVATE KEY")
+ || eqstr(name, "EC PRIVATE KEY")
+ || eqstr(name, "PRIVATE KEY"))
+ {
+ if (decode_key(pos[u].data,
+ pos[u].data_len,
+ print_text, print_C) < 0)
+ {
+ goto skey_exit_error;
+ }
+ } else {
+ if (verbose) {
+ fprintf(stderr,
+ "(skipping '%s')\n",
+ name);
+ }
+ }
+ }
+ for (u = 0; pos[u].name; u ++) {
+ free_pem_object_contents(&pos[u]);
+ }
+ xfree(pos);
+ pos = NULL;
+ }
+ xfree(buf);
+ buf = NULL;
+ }
+
+ /*
+ * Release allocated structures.
+ */
+skey_exit:
+ xfree(buf);
+ if (pos != NULL) {
+ size_t u;
+
+ for (u = 0; pos[u].name; u ++) {
+ free_pem_object_contents(&pos[u]);
+ }
+ xfree(pos);
+ }
+ return retcode;
+
+skey_exit_error:
+ retcode = -1;
+ goto skey_exit;
+}
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/poll.h>
+
+#include "brssl.h"
+#include "bearssl.h"
+
+static void
+dump_blob(const char *name, const void *data, size_t len)
+{
+ const unsigned char *buf;
+ size_t u;
+
+ buf = data;
+ fprintf(stderr, "%s (len = %lu)", name, (unsigned long)len);
+ for (u = 0; u < len; u ++) {
+ if ((u & 15) == 0) {
+ fprintf(stderr, "\n%08lX ", (unsigned long)u);
+ } else if ((u & 7) == 0) {
+ fprintf(stderr, " ");
+ }
+ fprintf(stderr, " %02x", buf[u]);
+ }
+ fprintf(stderr, "\n");
+}
+
+/*
+ * Inspect the provided data in case it is a "command" to trigger a
+ * special behaviour. If the command is recognised, then it is executed
+ * and this function returns 1. Otherwise, this function returns 0.
+ */
+static int
+run_command(br_ssl_engine_context *cc, unsigned char *buf, size_t len)
+{
+ if (len < 2 || len > 3) {
+ return 0;
+ }
+ if (len == 3 && (buf[1] != '\r' || buf[2] != '\n')) {
+ return 0;
+ }
+ if (len == 2 && buf[1] != '\n') {
+ return 0;
+ }
+ switch (buf[0]) {
+ case 'Q':
+ fprintf(stderr, "closing...\n");
+ br_ssl_engine_close(cc);
+ return 1;
+ case 'R':
+ fprintf(stderr, "renegotiating...\n");
+ br_ssl_engine_renegotiate(cc);
+ return 1;
+ case 'F':
+ /*
+ * Session forget is nominally client-only. But the
+ * session parameters are in the engine structure, which
+ * is the first field of the client context, so the cast
+ * still works properly. On the server, this forgetting
+ * has no effect.
+ */
+ fprintf(stderr, "forgetting session...\n");
+ br_ssl_client_forget_session((br_ssl_client_context *)cc);
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+/* see brssl.h */
+int
+run_ssl_engine(br_ssl_engine_context *cc, int fd, unsigned flags)
+{
+ int hsdetails;
+ int retcode;
+ int verbose;
+ int trace;
+
+ hsdetails = 0;
+ retcode = 0;
+ verbose = (flags & RUN_ENGINE_VERBOSE) != 0;
+ trace = (flags & RUN_ENGINE_TRACE) != 0;
+
+ /*
+ * Make sure that stdin and stdout are non-blocking.
+ */
+ fcntl(0, F_SETFL, O_NONBLOCK);
+ fcntl(1, F_SETFL, O_NONBLOCK);
+
+ /*
+ * Perform the loop.
+ */
+ for (;;) {
+ unsigned st;
+ int sendrec, recvrec, sendapp, recvapp;
+ struct pollfd pfd[3];
+ int n;
+ size_t u, k_fd, k_in, k_out;
+
+ /*
+ * Get current engine state.
+ */
+ st = br_ssl_engine_current_state(cc);
+ if (st == BR_SSL_CLOSED) {
+ int err;
+
+ err = br_ssl_engine_last_error(cc);
+ if (err == BR_ERR_OK) {
+ if (verbose) {
+ fprintf(stderr,
+ "SSL closed normally\n");
+ }
+ retcode = 0;
+ goto engine_exit;
+ } else {
+ fprintf(stderr, "ERROR: SSL error %d", err);
+ retcode = err;
+ if (err >= BR_ERR_SEND_FATAL_ALERT) {
+ err -= BR_ERR_SEND_FATAL_ALERT;
+ fprintf(stderr,
+ " (sent alert %d)\n", err);
+ } else if (err >= BR_ERR_RECV_FATAL_ALERT) {
+ err -= BR_ERR_RECV_FATAL_ALERT;
+ fprintf(stderr,
+ " (received alert %d)\n", err);
+ } else {
+ const char *ename;
+
+ ename = find_error_name(err, NULL);
+ if (ename == NULL) {
+ ename = "unknown";
+ }
+ fprintf(stderr, " (%s)\n", ename);
+ }
+ goto engine_exit;
+ }
+ }
+
+ /*
+ * Compute descriptors that must be polled, depending
+ * on engine state.
+ */
+ sendrec = ((st & BR_SSL_SENDREC) != 0);
+ recvrec = ((st & BR_SSL_RECVREC) != 0);
+ sendapp = ((st & BR_SSL_SENDAPP) != 0);
+ recvapp = ((st & BR_SSL_RECVAPP) != 0);
+ if (verbose && sendapp && !hsdetails) {
+ char csn[80];
+
+ fprintf(stderr, "Handshake completed\n");
+ fprintf(stderr, " version: ");
+ switch (cc->session.version) {
+ case BR_SSL30:
+ fprintf(stderr, "SSL 3.0");
+ break;
+ case BR_TLS10:
+ fprintf(stderr, "TLS 1.0");
+ break;
+ case BR_TLS11:
+ fprintf(stderr, "TLS 1.1");
+ break;
+ case BR_TLS12:
+ fprintf(stderr, "TLS 1.2");
+ break;
+ default:
+ fprintf(stderr, "unknown (0x%04X)",
+ (unsigned)cc->session.version);
+ break;
+ }
+ fprintf(stderr, "\n");
+ get_suite_name_ext(
+ cc->session.cipher_suite, csn, sizeof csn);
+ fprintf(stderr, " cipher suite: %s\n", csn);
+ fprintf(stderr, " secure renegotiation: %s\n",
+ cc->reneg == 1 ? "no" : "yes");
+ hsdetails = 1;
+ }
+
+ k_fd = 0;
+ k_in = 0;
+ k_out = 0;
+
+ u = 0;
+ if (sendrec || recvrec) {
+ pfd[u].fd = fd;
+ pfd[u].revents = 0;
+ pfd[u].events = 0;
+ if (sendrec) {
+ pfd[u].events |= POLLOUT;
+ }
+ if (recvrec) {
+ pfd[u].events |= POLLIN;
+ }
+ k_fd = u;
+ u ++;
+ }
+ if (sendapp) {
+ pfd[u].fd = 0;
+ pfd[u].revents = 0;
+ pfd[u].events = POLLIN;
+ k_in = u;
+ u ++;
+ }
+ if (recvapp) {
+ pfd[u].fd = 1;
+ pfd[u].revents = 0;
+ pfd[u].events = POLLOUT;
+ k_out = u;
+ u ++;
+ }
+ n = poll(pfd, u, -1);
+ if (n < 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+ perror("ERROR: poll()");
+ retcode = -2;
+ goto engine_exit;
+ }
+ if (n == 0) {
+ continue;
+ }
+
+ /*
+ * We transform closures/errors into read+write accesses
+ * so as to force the read() or write() call that will
+ * detect the situation.
+ */
+ while (u -- > 0) {
+ if (pfd[u].revents & (POLLERR | POLLHUP)) {
+ pfd[u].revents |= POLLIN | POLLOUT;
+ }
+ }
+
+ /*
+ * We give preference to outgoing data, on stdout and on
+ * the socket.
+ */
+ if (recvapp) {
+ if (pfd[k_out].revents & POLLOUT) {
+ unsigned char *buf;
+ size_t len;
+ ssize_t wlen;
+
+ buf = br_ssl_engine_recvapp_buf(cc, &len);
+ wlen = write(1, buf, len);
+ if (wlen <= 0) {
+ if (verbose) {
+ fprintf(stderr,
+ "stdout closed...\n");
+ }
+ retcode = -2;
+ goto engine_exit;
+ }
+ br_ssl_engine_recvapp_ack(cc, wlen);
+ continue;
+ }
+ }
+ if (sendrec) {
+ if (pfd[k_fd].revents & POLLOUT) {
+ unsigned char *buf;
+ size_t len;
+ ssize_t wlen;
+
+ buf = br_ssl_engine_sendrec_buf(cc, &len);
+ wlen = write(fd, buf, len);
+ if (wlen <= 0) {
+ if (verbose) {
+ fprintf(stderr,
+ "socket closed...\n");
+ }
+ retcode = -1;
+ goto engine_exit;
+ }
+ if (trace) {
+ dump_blob("Outgoing bytes", buf, wlen);
+ }
+ br_ssl_engine_sendrec_ack(cc, wlen);
+ continue;
+ }
+ }
+ if (recvrec) {
+ if (pfd[k_fd].revents & POLLIN) {
+ unsigned char *buf;
+ size_t len;
+ ssize_t rlen;
+
+ buf = br_ssl_engine_recvrec_buf(cc, &len);
+ rlen = read(fd, buf, len);
+ if (rlen <= 0) {
+ if (verbose) {
+ fprintf(stderr,
+ "socket closed...\n");
+ }
+ retcode = -1;
+ goto engine_exit;
+ }
+ if (trace) {
+ dump_blob("Incoming bytes", buf, rlen);
+ }
+ br_ssl_engine_recvrec_ack(cc, rlen);
+ continue;
+ }
+ }
+ if (sendapp) {
+ if (pfd[k_in].revents & POLLIN) {
+ unsigned char *buf;
+ size_t len;
+ ssize_t rlen;
+
+ buf = br_ssl_engine_sendapp_buf(cc, &len);
+ rlen = read(0, buf, len);
+ if (rlen <= 0) {
+ if (verbose) {
+ fprintf(stderr,
+ "stdin closed...\n");
+ }
+ br_ssl_engine_close(cc);
+ } else if (!run_command(cc, buf, rlen)) {
+ br_ssl_engine_sendapp_ack(cc, rlen);
+ }
+ br_ssl_engine_flush(cc, 0);
+ continue;
+ }
+ }
+
+ /* We should never reach that point. */
+ fprintf(stderr, "ERROR: poll() misbehaves\n");
+ retcode = -2;
+ goto engine_exit;
+ }
+
+ /*
+ * Release allocated structures.
+ */
+engine_exit:
+ return retcode;
+}
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include "brssl.h"
+#include "bearssl.h"
+
+static const char *
+curve_to_sym(int curve)
+{
+ switch (curve) {
+ case BR_EC_sect163k1: return "BR_EC_sect163k1";
+ case BR_EC_sect163r1: return "BR_EC_sect163r1";
+ case BR_EC_sect163r2: return "BR_EC_sect163r2";
+ case BR_EC_sect193r1: return "BR_EC_sect193r1";
+ case BR_EC_sect193r2: return "BR_EC_sect193r2";
+ case BR_EC_sect233k1: return "BR_EC_sect233k1";
+ case BR_EC_sect233r1: return "BR_EC_sect233r1";
+ case BR_EC_sect239k1: return "BR_EC_sect239k1";
+ case BR_EC_sect283k1: return "BR_EC_sect283k1";
+ case BR_EC_sect283r1: return "BR_EC_sect283r1";
+ case BR_EC_sect409k1: return "BR_EC_sect409k1";
+ case BR_EC_sect409r1: return "BR_EC_sect409r1";
+ case BR_EC_sect571k1: return "BR_EC_sect571k1";
+ case BR_EC_sect571r1: return "BR_EC_sect571r1";
+ case BR_EC_secp160k1: return "BR_EC_secp160k1";
+ case BR_EC_secp160r1: return "BR_EC_secp160r1";
+ case BR_EC_secp160r2: return "BR_EC_secp160r2";
+ case BR_EC_secp192k1: return "BR_EC_secp192k1";
+ case BR_EC_secp192r1: return "BR_EC_secp192r1";
+ case BR_EC_secp224k1: return "BR_EC_secp224k1";
+ case BR_EC_secp224r1: return "BR_EC_secp224r1";
+ case BR_EC_secp256k1: return "BR_EC_secp256k1";
+ case BR_EC_secp256r1: return "BR_EC_secp256r1";
+ case BR_EC_secp384r1: return "BR_EC_secp384r1";
+ case BR_EC_secp521r1: return "BR_EC_secp521r1";
+ case BR_EC_brainpoolP256r1: return "BR_EC_brainpoolP256r1";
+ case BR_EC_brainpoolP384r1: return "BR_EC_brainpoolP384r1";
+ case BR_EC_brainpoolP512r1: return "BR_EC_brainpoolP512r1";
+ }
+ return NULL;
+}
+
+static void
+print_blob(const char *name, const unsigned char *buf, size_t len)
+{
+ size_t u;
+
+ printf("\nstatic const unsigned char %s[] = {", name);
+ for (u = 0; u < len; u ++) {
+ if (u != 0) {
+ printf(",");
+ }
+ if (u % 12 == 0) {
+ printf("\n\t");
+ } else {
+ printf(" ");
+ }
+ printf("0x%02X", buf[u]);
+ }
+ printf("\n};\n");
+}
+
+static int
+print_ta_internals(br_x509_trust_anchor *ta, long ctr)
+{
+ char tmp[25];
+
+ sprintf(tmp, "TA%ld_DN", ctr);
+ print_blob(tmp, ta->dn, ta->dn_len);
+ switch (ta->pkey.key_type) {
+ case BR_KEYTYPE_RSA:
+ sprintf(tmp, "TA%ld_RSA_N", ctr);
+ print_blob(tmp, ta->pkey.key.rsa.n, ta->pkey.key.rsa.nlen);
+ sprintf(tmp, "TA%ld_RSA_E", ctr);
+ print_blob(tmp, ta->pkey.key.rsa.e, ta->pkey.key.rsa.elen);
+ break;
+ case BR_KEYTYPE_EC:
+ sprintf(tmp, "TA%ld_EC_Q", ctr);
+ print_blob(tmp, ta->pkey.key.ec.q, ta->pkey.key.ec.qlen);
+ break;
+ default:
+ fprintf(stderr, "ERROR: unknown anchor key type '%d'\n",
+ ta->pkey.key_type);
+ return -1;
+ }
+ return 0;
+}
+
+static void
+print_ta(br_x509_trust_anchor *ta, long ctr)
+{
+ char tmp[25];
+
+ printf("\t{\n");
+ printf("\t\t(unsigned char *)TA%ld_DN, sizeof TA%ld_DN,\n", ctr, ctr);
+ printf("\t\t%s,\n", (ta->flags & BR_X509_TA_CA)
+ ? "BR_X509_TA_CA" : "0");
+ printf("\t\t{\n");
+ switch (ta->pkey.key_type) {
+ const char *cname;
+
+ case BR_KEYTYPE_RSA:
+ printf("\t\t\tBR_KEYTYPE_RSA,\n");
+ printf("\t\t\t{ .rsa = {\n");
+ printf("\t\t\t\t(unsigned char *)TA%ld_RSA_N,"
+ " sizeof TA%ld_RSA_N,\n", ctr, ctr);
+ printf("\t\t\t\t(unsigned char *)TA%ld_RSA_E,"
+ " sizeof TA%ld_RSA_E,\n", ctr, ctr);
+ printf("\t\t\t} }\n");
+ break;
+ case BR_KEYTYPE_EC:
+ printf("\t\t\tBR_KEYTYPE_EC,\n");
+ printf("\t\t\t{ .ec = {\n");
+ cname = curve_to_sym(ta->pkey.key.ec.curve);
+ if (cname == NULL) {
+ sprintf(tmp, "%d", ta->pkey.key.ec.curve);
+ cname = tmp;
+ }
+ printf("\t\t\t\t%s,\n", cname);
+ printf("\t\t\t\t(unsigned char *)TA%ld_EC_Q,"
+ " sizeof TA%ld_EC_Q,\n", ctr, ctr);
+ printf("\t\t\t} }\n");
+ }
+ printf("\t\t}\n");
+ printf("\t}");
+}
+
+static void
+usage_ta(void)
+{
+ fprintf(stderr,
+"usage: brssl ta [ options ] file...\n");
+ fprintf(stderr,
+"options:\n");
+ fprintf(stderr,
+" -q suppress verbose messages\n");
+}
+
+/* see brssl.h */
+int
+do_ta(int argc, char *argv[])
+{
+ int retcode;
+ int verbose;
+ int i, num_files;
+ anchor_list tas = VEC_INIT;
+ size_t u, num;
+
+ retcode = 0;
+ verbose = 1;
+ num_files = 0;
+ for (i = 0; i < argc; i ++) {
+ const char *arg;
+
+ arg = argv[i];
+ if (arg[0] != '-') {
+ num_files ++;
+ continue;
+ }
+ argv[i] = NULL;
+ if (eqstr(arg, "-v") || eqstr(arg, "-verbose")) {
+ verbose = 1;
+ } else if (eqstr(arg, "-q") || eqstr(arg, "-quiet")) {
+ verbose = 0;
+ } else {
+ fprintf(stderr, "ERROR: unknown option: '%s'\n", arg);
+ usage_ta();
+ goto ta_exit_error;
+ }
+ }
+ if (num_files == 0) {
+ fprintf(stderr, "ERROR: no certificate file provided\n");
+ usage_ta();
+ goto ta_exit_error;
+ }
+
+ for (i = 0; i < argc; i ++) {
+ const char *fname;
+ size_t len1, len2;
+
+ fname = argv[i];
+ if (fname == NULL) {
+ continue;
+ }
+ if (verbose) {
+ fprintf(stderr, "Reading file '%s': ", fname);
+ fflush(stderr);
+ }
+ len1 = VEC_LEN(tas);
+ if (read_trust_anchors(&tas, fname) == 0) {
+ goto ta_exit_error;
+ }
+ len2 = VEC_LEN(tas) - len1;
+ if (verbose) {
+ fprintf(stderr, "%lu trust anchor%s\n",
+ (unsigned long)len2, len2 > 1 ? "s" : "");
+ }
+ }
+ num = VEC_LEN(tas);
+ for (u = 0; u < num; u ++) {
+ if (print_ta_internals(&VEC_ELT(tas, u), u) < 0) {
+ goto ta_exit_error;
+ }
+ }
+ printf("\nstatic const br_x509_trust_anchor TAs[%ld] = {", (long)num);
+ for (u = 0; u < num; u ++) {
+ if (u != 0) {
+ printf(",");
+ }
+ printf("\n");
+ print_ta(&VEC_ELT(tas, u), u);
+ }
+ printf("\n};\n");
+ printf("\n#define TAs_NUM %ld\n", (long)num);
+
+ /*
+ * Release allocated structures.
+ */
+ta_exit:
+ VEC_CLEAREXT(tas, free_ta_contents);
+ return retcode;
+
+ta_exit_error:
+ retcode = -1;
+ goto ta_exit;
+}
--- /dev/null
+/*
+ * 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 "brssl.h"
+
+/*
+ * Prepare a vector buffer for adding 'extra' elements.
+ * buf current buffer
+ * esize size of a vector element
+ * ptr pointer to the 'ptr' vector field
+ * len pointer to the 'len' vector field
+ * extra number of elements to add
+ *
+ * If the buffer must be enlarged, then this function allocates the new
+ * buffer and releases the old one. The new buffer address is then returned.
+ * If the buffer needs not be enlarged, then the buffer address is returned.
+ *
+ * In case of enlargement, the 'len' field is adjusted accordingly. The
+ * 'ptr' field is not modified.
+ */
+void *
+vector_expand(void *buf,
+ size_t esize, size_t *ptr, size_t *len, size_t extra)
+{
+ size_t nlen;
+ void *nbuf;
+
+ if (*len - *ptr >= extra) {
+ return buf;
+ }
+ nlen = (*len << 1);
+ if (nlen - *ptr < extra) {
+ nlen = extra + *ptr;
+ if (nlen < 8) {
+ nlen = 8;
+ }
+ }
+ nbuf = xmalloc(nlen * esize);
+ if (buf != NULL) {
+ memcpy(nbuf, buf, *len * esize);
+ xfree(buf);
+ }
+ *len = nlen;
+ return nbuf;
+}
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include "brssl.h"
+#include "bearssl.h"
+
+static unsigned
+rsa_bit_length(const br_rsa_public_key *pk)
+{
+ size_t u;
+ unsigned x, bl;
+
+ for (u = 0; u < pk->nlen; u ++) {
+ if (pk->n[u] != 0) {
+ break;
+ }
+ }
+ if (u == pk->nlen) {
+ return 0;
+ }
+ bl = (unsigned)(pk->nlen - u - 1) << 3;
+ x = pk->n[u];
+ while (x != 0) {
+ bl ++;
+ x >>= 1;
+ }
+ return bl;
+}
+
+static void
+print_rsa(const br_rsa_public_key *pk, int print_text, int print_C)
+{
+ if (print_text) {
+ size_t u;
+
+ printf("n = ");
+ for (u = 0; u < pk->nlen; u ++) {
+ printf("%02X", pk->n[u]);
+ }
+ printf("\n");
+ printf("e = ");
+ for (u = 0; u < pk->elen; u ++) {
+ printf("%02X", pk->e[u]);
+ }
+ printf("\n");
+ }
+ if (print_C) {
+ size_t u;
+
+ printf("\nstatic const unsigned char RSA_N[] = {");
+ for (u = 0; u < pk->nlen; u ++) {
+ if (u != 0) {
+ printf(",");
+ }
+ if (u % 12 == 0) {
+ printf("\n\t");
+ } else {
+ printf(" ");
+ }
+ printf("0x%02X", pk->n[u]);
+ }
+ printf("\n};\n");
+ printf("\nstatic const unsigned char RSA_E[] = {");
+ for (u = 0; u < pk->elen; u ++) {
+ if (u != 0) {
+ printf(",");
+ }
+ if (u % 12 == 0) {
+ printf("\n\t");
+ } else {
+ printf(" ");
+ }
+ printf("0x%02X", pk->e[u]);
+ }
+ printf("\n};\n");
+ printf("\nstatic const br_rsa_public_key RSA = {\n");
+ printf("\t(unsigned char *)RSA_N, sizeof RSA_N,\n");
+ printf("\t(unsigned char *)RSA_E, sizeof RSA_E\n");
+ printf("};\n");
+ }
+}
+
+static void
+print_ec(const br_ec_public_key *pk, int print_text, int print_C)
+{
+ if (print_text) {
+ size_t u;
+
+ printf("Q = ");
+ for (u = 0; u < pk->qlen; u ++) {
+ printf("%02X", pk->q[u]);
+ }
+ printf("\n");
+ }
+ if (print_C) {
+ size_t u;
+
+ printf("\nstatic const unsigned char EC_Q[] = {");
+ for (u = 0; u < pk->qlen; u ++) {
+ if (u != 0) {
+ printf(",");
+ }
+ if (u % 12 == 0) {
+ printf("\n\t");
+ } else {
+ printf(" ");
+ }
+ printf("0x%02X", pk->q[u]);
+ }
+ printf("\n};\n");
+ printf("\nstatic const br_ec_public_key EC = {\n");
+ printf("\t%d,\n", pk->curve);
+ printf("\t(unsigned char *)EC_Q, sizeof EC_Q\n");
+ printf("};\n");
+ }
+}
+
+static void
+usage_verify(void)
+{
+ fprintf(stderr,
+"usage: brssl verify [ options ] file...\n");
+ fprintf(stderr,
+"options:\n");
+ fprintf(stderr,
+" -q suppress verbose messages\n");
+ fprintf(stderr,
+" -sni name check presence of a specific server name\n");
+ fprintf(stderr,
+" -CA file add certificates in 'file' to trust anchors\n");
+ fprintf(stderr,
+" -text print public key details (human-readable)\n");
+ fprintf(stderr,
+" -C print public key details (C code)\n");
+}
+
+typedef VECTOR(br_x509_certificate) cert_list;
+
+static void
+free_cert_contents(br_x509_certificate *xc)
+{
+ xfree(xc->data);
+}
+
+/* see brssl.h */
+int
+do_verify(int argc, char *argv[])
+{
+ int retcode;
+ int verbose;
+ int i;
+ const char *sni;
+ anchor_list anchors = VEC_INIT;
+ cert_list chain = VEC_INIT;
+ size_t u;
+ br_x509_minimal_context mc;
+ int err_keyx, err_sign;
+ int print_text, print_C;
+ br_x509_pkey *pk;
+
+ retcode = 0;
+ verbose = 1;
+ sni = NULL;
+ print_text = 0;
+ print_C = 0;
+ pk = NULL;
+ err_keyx = 0;
+ err_sign = 0;
+ for (i = 0; i < argc; i ++) {
+ const char *arg;
+
+ arg = argv[i];
+ if (arg[0] != '-') {
+ br_x509_certificate *xcs;
+ size_t num;
+
+ xcs = read_certificates(arg, &num);
+ if (xcs == NULL) {
+ usage_verify();
+ goto verify_exit_error;
+ }
+ VEC_ADDMANY(chain, xcs, num);
+ xfree(xcs);
+ continue;
+ }
+ if (eqstr(arg, "-v") || eqstr(arg, "-verbose")) {
+ verbose = 1;
+ } else if (eqstr(arg, "-q") || eqstr(arg, "-quiet")) {
+ verbose = 0;
+ } else if (eqstr(arg, "-sni")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-sni'\n");
+ usage_verify();
+ goto verify_exit_error;
+ }
+ if (sni != NULL) {
+ fprintf(stderr, "ERROR: duplicate SNI\n");
+ usage_verify();
+ goto verify_exit_error;
+ }
+ sni = argv[i];
+ continue;
+ } else if (eqstr(arg, "-CA")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-CA'\n");
+ usage_verify();
+ goto verify_exit_error;
+ }
+ arg = argv[i];
+ if (read_trust_anchors(&anchors, arg) == 0) {
+ usage_verify();
+ goto verify_exit_error;
+ }
+ continue;
+ } else if (eqstr(arg, "-text")) {
+ print_text = 1;
+ } else if (eqstr(arg, "-C")) {
+ print_C = 1;
+ } else {
+ fprintf(stderr, "ERROR: unknown option: '%s'\n", arg);
+ usage_verify();
+ goto verify_exit_error;
+ }
+ }
+ if (VEC_LEN(chain) == 0) {
+ fprintf(stderr, "ERROR: no certificate chain provided\n");
+ usage_verify();
+ goto verify_exit_error;
+ }
+ br_x509_minimal_init(&mc, &br_sha256_vtable,
+ &VEC_ELT(anchors, 0), VEC_LEN(anchors));
+ br_x509_minimal_set_hash(&mc, br_sha1_ID, &br_sha1_vtable);
+ br_x509_minimal_set_hash(&mc, br_sha224_ID, &br_sha224_vtable);
+ br_x509_minimal_set_hash(&mc, br_sha256_ID, &br_sha256_vtable);
+ br_x509_minimal_set_hash(&mc, br_sha384_ID, &br_sha384_vtable);
+ br_x509_minimal_set_hash(&mc, br_sha512_ID, &br_sha512_vtable);
+ br_x509_minimal_set_rsa(&mc, &br_rsa_i31_pkcs1_vrfy);
+ br_x509_minimal_set_ecdsa(&mc,
+ &br_ec_prime_i31, &br_ecdsa_i31_vrfy_asn1);
+ for (i = 0; i < 2; i ++) {
+ const br_x509_pkey *tpk;
+ int err;
+
+ mc.vtable->start_chain(&mc.vtable,
+ i == 0 ? BR_KEYTYPE_KEYX : BR_KEYTYPE_SIGN, sni);
+ for (u = 0; u < VEC_LEN(chain); u ++) {
+ br_x509_certificate *xc;
+
+ xc = &VEC_ELT(chain, u);
+ mc.vtable->start_cert(&mc.vtable, xc->data_len);
+ mc.vtable->append(&mc.vtable, xc->data, xc->data_len);
+ mc.vtable->end_cert(&mc.vtable);
+ }
+ err = mc.vtable->end_chain(&mc.vtable);
+ if (i == 0) {
+ err_keyx = err;
+ } else {
+ err_sign = err;
+ }
+ tpk = mc.vtable->get_pkey(&mc.vtable);
+ if (pk == NULL && tpk != NULL) {
+ pk = xpkeydup(tpk);
+ }
+ }
+ if (err_keyx == 0 || err_sign == 0) {
+ if (verbose) {
+ fprintf(stderr, "Validation success");
+ if (err_keyx == 0 && err_sign == 0) {
+ fprintf(stderr, " (key exchange, sign)\n");
+ } else if (err_keyx == 0) {
+ fprintf(stderr, " (key exchange)\n");
+ } else if (err_sign == 0) {
+ fprintf(stderr, " (signature)\n");
+ }
+ }
+ } else {
+ if (verbose) {
+ int err;
+ const char *errname, *errmsg;
+
+ /*
+ * If the two error codes differ, we want the one
+ * which is not a "forbidden key usage".
+ */
+ err = err_keyx;
+ if (err == BR_ERR_X509_FORBIDDEN_KEY_USAGE) {
+ err = err_sign;
+ }
+ fprintf(stderr, "Validation failed, err = %d", err);
+ errname = find_error_name(err, &errmsg);
+ if (errname != NULL) {
+ fprintf(stderr, " (%s): %s\n", errname, errmsg);
+ } else {
+ fprintf(stderr, " (unknown)\n");
+ }
+ }
+ retcode = -1;
+ }
+ if (pk != NULL) {
+ switch (pk->key_type) {
+ case BR_KEYTYPE_RSA:
+ if (verbose) {
+ fprintf(stderr, "Key type: RSA (%u bits)\n",
+ rsa_bit_length(&pk->key.rsa));
+ }
+ print_rsa(&pk->key.rsa, print_text, print_C);
+ break;
+ case BR_KEYTYPE_EC:
+ if (verbose) {
+ fprintf(stderr, "Key type: EC (%s)\n",
+ ec_curve_name(pk->key.ec.curve));
+ }
+ print_ec(&pk->key.ec, print_text, print_C);
+ break;
+ default:
+ if (verbose) {
+ fprintf(stderr, "Unknown key type\n");
+ break;
+ }
+ }
+ }
+
+ /*
+ * Release allocated structures.
+ */
+verify_exit:
+ VEC_CLEAREXT(anchors, &free_ta_contents);
+ VEC_CLEAREXT(chain, &free_cert_contents);
+ xfreepkey(pk);
+ return retcode;
+
+verify_exit_error:
+ retcode = -1;
+ goto verify_exit;
+}
--- /dev/null
+/*
+ * 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 "brssl.h"
+
+/* see brssl.h */
+void *
+xmalloc(size_t len)
+{
+ void *buf;
+
+ if (len == 0) {
+ return NULL;
+ }
+ buf = malloc(len);
+ if (buf == NULL) {
+ fprintf(stderr, "ERROR: could not allocate %lu byte(s)\n",
+ (unsigned long)len);
+ exit(EXIT_FAILURE);
+ }
+ return buf;
+}
+
+/* see brssl.h */
+void
+xfree(void *buf)
+{
+ if (buf != NULL) {
+ free(buf);
+ }
+}
+
+/* see brssl.h */
+void *
+xblobdup(const void *src, size_t len)
+{
+ void *buf;
+
+ buf = xmalloc(len);
+ memcpy(buf, src, len);
+ return buf;
+}
+
+/* see brssl.h */
+char *
+xstrdup(const void *src)
+{
+ return xblobdup(src, strlen(src) + 1);
+}
+
+/* see brssl.h */
+br_x509_pkey *
+xpkeydup(const br_x509_pkey *pk)
+{
+ br_x509_pkey *pk2;
+
+ pk2 = xmalloc(sizeof *pk2);
+ pk2->key_type = pk->key_type;
+ switch (pk->key_type) {
+ case BR_KEYTYPE_RSA:
+ pk2->key.rsa.n = xblobdup(pk->key.rsa.n, pk->key.rsa.nlen);
+ pk2->key.rsa.nlen = pk->key.rsa.nlen;
+ pk2->key.rsa.e = xblobdup(pk->key.rsa.e, pk->key.rsa.elen);
+ pk2->key.rsa.elen = pk->key.rsa.elen;
+ break;
+ case BR_KEYTYPE_EC:
+ pk2->key.ec.curve = pk->key.ec.curve;
+ pk2->key.ec.q = xblobdup(pk->key.ec.q, pk->key.ec.qlen);
+ pk2->key.ec.qlen = pk->key.ec.qlen;
+ break;
+ default:
+ fprintf(stderr, "Unknown public key type: %u\n",
+ (unsigned)pk->key_type);
+ exit(EXIT_FAILURE);
+ }
+ return pk2;
+}
+
+/* see brssl.h */
+void
+xfreepkey(br_x509_pkey *pk)
+{
+ if (pk != NULL) {
+ switch (pk->key_type) {
+ case BR_KEYTYPE_RSA:
+ xfree(pk->key.rsa.n);
+ xfree(pk->key.rsa.e);
+ break;
+ case BR_KEYTYPE_EC:
+ xfree(pk->key.ec.q);
+ break;
+ default:
+ fprintf(stderr, "Unknown public key type: %u\n",
+ (unsigned)pk->key_type);
+ exit(EXIT_FAILURE);
+ }
+ xfree(pk);
+ }
+}