Initial import.

This commit is contained in:
Thomas Pornin 2016-11-02 19:01:13 -04:00
commit 3210f38e04
292 changed files with 58526 additions and 0 deletions

21
LICENSE.txt Normal file
View file

@ -0,0 +1,21 @@
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.

606
Makefile Normal file
View file

@ -0,0 +1,606 @@
# 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

169
README.txt Normal file
View file

@ -0,0 +1,169 @@
# 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.

112
T0/BlobWriter.cs Normal file
View file

@ -0,0 +1,112 @@
/*
* 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;
}
}

181
T0/CPU.cs Normal file
View file

@ -0,0 +1,181 @@
/*
* 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];
}
}
}

88
T0/CodeElement.cs Normal file
View file

@ -0,0 +1,88 @@
/*
* 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;
}
}

78
T0/CodeElementJump.cs Normal file
View file

@ -0,0 +1,78 @@
/*
* 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);
}
}

46
T0/CodeElementUInt.cs Normal file
View file

@ -0,0 +1,46 @@
/*
* 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);
}
}

56
T0/CodeElementUIntExpr.cs Normal file
View file

@ -0,0 +1,56 @@
/*
* 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;
}
}

51
T0/CodeElementUIntInt.cs Normal file
View file

@ -0,0 +1,51 @@
/*
* 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;
}
}

50
T0/CodeElementUIntUInt.cs Normal file
View file

@ -0,0 +1,50 @@
/*
* 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;
}
}

198
T0/ConstData.cs Normal file
View file

@ -0,0 +1,198 @@
/*
* 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]);
}
}
}

117
T0/Opcode.cs Normal file
View file

@ -0,0 +1,117 @@
/*
* 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)
{
}
}

71
T0/OpcodeCall.cs Normal file
View file

@ -0,0 +1,71 @@
/*
* 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);
}
}

95
T0/OpcodeConst.cs Normal file
View file

@ -0,0 +1,95 @@
/*
* 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();
}
}

57
T0/OpcodeGetLocal.cs Normal file
View file

@ -0,0 +1,57 @@
/*
* 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;
}
}

64
T0/OpcodeJump.cs Normal file
View file

@ -0,0 +1,64 @@
/*
* 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]);
}
}

65
T0/OpcodeJumpIf.cs Normal file
View file

@ -0,0 +1,65 @@
/*
* 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;
}
}
}

65
T0/OpcodeJumpIfNot.cs Normal file
View file

@ -0,0 +1,65 @@
/*
* 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;
}
}
}

61
T0/OpcodeJumpUncond.cs Normal file
View file

@ -0,0 +1,61 @@
/*
* 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;
}
}
}

57
T0/OpcodePutLocal.cs Normal file
View file

@ -0,0 +1,57 @@
/*
* 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;
}
}

50
T0/OpcodeRet.cs Normal file
View file

@ -0,0 +1,50 @@
/*
* 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";
}
}

129
T0/SType.cs Normal file
View file

@ -0,0 +1,129 @@
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);
}
}

2070
T0/T0Comp.cs Normal file

File diff suppressed because it is too large Load diff

64
T0/TPointerBase.cs Normal file
View file

@ -0,0 +1,64 @@
/*
* 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;
}
}

75
T0/TPointerBlob.cs Normal file
View file

@ -0,0 +1,75 @@
/*
* 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;
}
}

97
T0/TPointerExpr.cs Normal file
View file

@ -0,0 +1,97 @@
/*
* 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;
}
}

44
T0/TPointerNull.cs Normal file
View file

@ -0,0 +1,44 @@
/*
* 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;
}
}

73
T0/TPointerXT.cs Normal file
View file

@ -0,0 +1,73 @@
/*
* 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;
}
}

231
T0/TValue.cs Normal file
View file

@ -0,0 +1,231 @@
/*
* 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;
}
}

172
T0/Word.cs Normal file
View file

@ -0,0 +1,172 @@
/*
* 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;
}
}
}

385
T0/WordBuilder.cs Normal file
View file

@ -0,0 +1,385 @@
/*
* 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));
}
}

96
T0/WordData.cs Normal file
View file

@ -0,0 +1,96 @@
/*
* 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));
}
}

283
T0/WordInterpreted.cs Normal file
View file

@ -0,0 +1,283 @@
/*
* 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;
}
}
}

59
T0/WordNative.cs Normal file
View file

@ -0,0 +1,59 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
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);
}
}

309
T0/kern.t0 Normal file
View file

@ -0,0 +1,309 @@
: \ `\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));
}

BIN
T0Comp.exe Executable file

Binary file not shown.

0
build/.do_not_remove Normal file
View file

42
inc/bearssl.h Normal file
View file

@ -0,0 +1,42 @@
/*
* 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

476
inc/bearssl_block.h Normal file
View file

@ -0,0 +1,476 @@
/*
* 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

220
inc/bearssl_ec.h Normal file
View file

@ -0,0 +1,220 @@
/*
* 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

424
inc/bearssl_hash.h Normal file
View file

@ -0,0 +1,424 @@
/*
* 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

148
inc/bearssl_hmac.h Normal file
View file

@ -0,0 +1,148 @@
/*
* 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

125
inc/bearssl_pem.h Normal file
View file

@ -0,0 +1,125 @@
/*
* 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

66
inc/bearssl_prf.h Normal file
View file

@ -0,0 +1,66 @@
/*
* 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

149
inc/bearssl_rand.h Normal file
View file

@ -0,0 +1,149 @@
/*
* 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

227
inc/bearssl_rsa.h Normal file
View file

@ -0,0 +1,227 @@
/*
* 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

1856
inc/bearssl_ssl.h Normal file

File diff suppressed because it is too large Load diff

733
inc/bearssl_x509.h Normal file
View file

@ -0,0 +1,733 @@
/*
* 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

11
mkT0.sh Executable file
View file

@ -0,0 +1,11 @@
#! /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

36
samples/README.txt Normal file
View file

@ -0,0 +1,36 @@
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.

View file

@ -0,0 +1,14 @@
-----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-----

10
samples/cert-ee-ec.pem Normal file
View file

@ -0,0 +1,10 @@
-----BEGIN CERTIFICATE-----
MIIBsDCCAVagAwIBAgIUHE0AkWniRqyQfGRcU/H/t8HLbnowCgYIKoZIzj0EAwIwJzELMAkGA1UE
BhMCQ0ExGDAWBgNVBAMTD0ludGVybWVkaWF0ZSBDQTAeFw0xMDAxMDEwMDAwMDBaFw0zNzEyMzEy
MzU5NTlaMCExCzAJBgNVBAYTAkNBMRIwEAYDVQQDEwlsb2NhbGhvc3QwWTATBgcqhkjOPQIBBggq
hkjOPQMBBwNCAARfOJ2n/02Kr/Y0OUYa/Drf9COqqer7xQjeAI6+eaU3WExt3QHKq0ffibbHFx84
/B0gFN1FwOCPk044C/zpmaFJo2YwZDAfBgNVHSMEGDAWgBTw0PEi+XpIFwZ7Pb249c1VnFw+cDAd
BgNVHQ4EFgQUww6GqnW0FcDllQkyvl6SdankRJswDAYDVR0TAQH/BAIwADAUBgNVHREEDTALggls
b2NhbGhvc3QwCgYIKoZIzj0EAwIDSAAwRQIhAJH79ATQ5S4B1IzwF2IP3MyAyhjEQHwnA8s0Aw2b
yFlNAiAFVWni2KFAMzQOfkkyZB0/ax/QLbcvUgRWr9M3j4eZog==
-----END CERTIFICATE-----

17
samples/cert-ee-rsa.pem Normal file
View file

@ -0,0 +1,17 @@
-----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-----

10
samples/cert-ica-ec.pem Normal file
View file

@ -0,0 +1,10 @@
-----BEGIN CERTIFICATE-----
MIIBqTCCAU6gAwIBAgIUINPr4oz+2uajLF478mY6KzZ7sMowCgYIKoZIzj0EAwIwHDELMAkGA1UE
BhMCQ0ExDTALBgNVBAMTBFJvb3QwHhcNMTAwMTAxMDAwMDAwWhcNMzcxMjMxMjM1OTU5WjAnMQsw
CQYDVQQGEwJDQTEYMBYGA1UEAxMPSW50ZXJtZWRpYXRlIENBMFkwEwYHKoZIzj0CAQYIKoZIzj0D
AQcDQgAEcC6SggEXbG2r4dFjCUhJ0qY1UtM8c7uyiDeYh/GN4Oxlmg4T9e2RYci2bTOEbq6OVYDN
SZ4Hv9CunebQsycWoaNjMGEwHwYDVR0jBBgwFoAUlUG04meq8X+8j3nzaBRaa5IWokAwHQYDVR0O
BBYEFPDQ8SL5ekgXBns9vbj1zVWcXD5wMA4GA1UdDwEB/wQEAwIAhjAPBgNVHRMBAf8EBTADAQH/
MAoGCCqGSM49BAMCA0kAMEYCIQCF40ZomdYCellmHLdPNS0INjhhfgVI2GlDH+tW6a0GDgIhAIJw
tGIDSUbIVFkF2XjbUxzgbmb1DxQ7yS04EnCRVvmp
-----END CERTIFICATE-----

17
samples/cert-ica-rsa.pem Normal file
View file

@ -0,0 +1,17 @@
-----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-----

9
samples/cert-root-ec.pem Normal file
View file

@ -0,0 +1,9 @@
-----BEGIN CERTIFICATE-----
MIIBijCCATCgAwIBAgIBCTAKBggqhkjOPQQDAjAcMQswCQYDVQQGEwJDQTENMAsGA1UEAxMEUm9v
dDAeFw0xMDAxMDEwMDAwMDBaFw0zNzEyMzEyMzU5NTlaMBwxCzAJBgNVBAYTAkNBMQ0wCwYDVQQD
EwRSb290MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEcXS6q7kwLoHV5Vf58yBoDJz5ZNu0IA1t
6kDQSm5C/baaaCVE9t97xPze3Xu7xdt8dj9BZkBu26eHwuXYxfN/jaNjMGEwHwYDVR0jBBgwFoAU
lUG04meq8X+8j3nzaBRaa5IWokAwHQYDVR0OBBYEFJVBtOJnqvF/vI9582gUWmuSFqJAMA4GA1Ud
DwEB/wQEAwIAhjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0gAMEUCIQCz1GCIAoRtqU2h
x62hec7E+/XxnUGDORWnkliiGrcmxQIgNPq9NHD7ts0xYjTwZsd0bN62+iY93lM4LHbkNV9q/gA=
-----END CERTIFICATE-----

16
samples/cert-root-rsa.pem Normal file
View file

@ -0,0 +1,16 @@
-----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-----

166
samples/chain-ec+rsa.h Normal file
View file

@ -0,0 +1,166 @@
/*
* 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

117
samples/chain-ec.h Normal file
View file

@ -0,0 +1,117 @@
/*
* 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

183
samples/chain-rsa.h Normal file
View file

@ -0,0 +1,183 @@
/*
* 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

374
samples/client_basic.c Normal file
View file

@ -0,0 +1,374 @@
/*
* 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;
}
}

529
samples/custom_profile.c Normal file
View file

@ -0,0 +1,529 @@
/*
* 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);
*/
}

40
samples/key-ec.h Normal file
View file

@ -0,0 +1,40 @@
/*
* 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
};

5
samples/key-ee-ec.pem Normal file
View file

@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIAORW0IGkHORG0jvCPu1rXVl+eb3IUdiSPo/l3twnYaloAoGCCqGSM49AwEHoUQDQgAE
Xzidp/9Niq/2NDlGGvw63/Qjqqnq+8UI3gCOvnmlN1hMbd0ByqtH34m2xxcfOPwdIBTdRcDgj5NO
OAv86ZmhSQ==
-----END EC PRIVATE KEY-----

23
samples/key-ee-rsa.pem Normal file
View file

@ -0,0 +1,23 @@
-----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-----

5
samples/key-ica-ec.pem Normal file
View file

@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIEJOkvo4MZ9N+wlTodEzmWor1RauybudPe92K15viDbzoAoGCCqGSM49AwEHoUQDQgAE
cC6SggEXbG2r4dFjCUhJ0qY1UtM8c7uyiDeYh/GN4Oxlmg4T9e2RYci2bTOEbq6OVYDNSZ4Hv9Cu
nebQsycWoQ==
-----END EC PRIVATE KEY-----

23
samples/key-ica-rsa.pem Normal file
View file

@ -0,0 +1,23 @@
-----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-----

5
samples/key-root-ec.pem Normal file
View file

@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEINx41f6h/utlj52XNFbIGJdkF3qZy1/g9hH2/yV4t/tnoAoGCCqGSM49AwEHoUQDQgAE
cXS6q7kwLoHV5Vf58yBoDJz5ZNu0IA1t6kDQSm5C/baaaCVE9t97xPze3Xu7xdt8dj9BZkBu26eH
wuXYxfN/jQ==
-----END EC PRIVATE KEY-----

23
samples/key-root-rsa.pem Normal file
View file

@ -0,0 +1,23 @@
-----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-----

108
samples/key-rsa.h Normal file
View file

@ -0,0 +1,108 @@
/*
* 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
};

402
samples/server_basic.c Normal file
View file

@ -0,0 +1,402 @@
/*
* 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);
}
}

44
src/codec/ccopy.c Normal file
View file

@ -0,0 +1,44 @@
/*
* 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 ++;
}
}

38
src/codec/dec16be.c Normal file
View file

@ -0,0 +1,38 @@
/*
* 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;
}
}

38
src/codec/dec16le.c Normal file
View file

@ -0,0 +1,38 @@
/*
* 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;
}
}

38
src/codec/dec32be.c Normal file
View file

@ -0,0 +1,38 @@
/*
* 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;
}
}

38
src/codec/dec32le.c Normal file
View file

@ -0,0 +1,38 @@
/*
* 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;
}
}

38
src/codec/dec64be.c Normal file
View file

@ -0,0 +1,38 @@
/*
* 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;
}
}

38
src/codec/dec64le.c Normal file
View file

@ -0,0 +1,38 @@
/*
* 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;
}
}

38
src/codec/enc16be.c Normal file
View file

@ -0,0 +1,38 @@
/*
* 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;
}
}

38
src/codec/enc16le.c Normal file
View file

@ -0,0 +1,38 @@
/*
* 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;
}
}

38
src/codec/enc32be.c Normal file
View file

@ -0,0 +1,38 @@
/*
* 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;
}
}

38
src/codec/enc32le.c Normal file
View file

@ -0,0 +1,38 @@
/*
* 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;
}
}

38
src/codec/enc64be.c Normal file
View file

@ -0,0 +1,38 @@
/*
* 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;
}
}

38
src/codec/enc64le.c Normal file
View file

@ -0,0 +1,38 @@
/*
* 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;
}
}

508
src/codec/pemdec.c Normal file
View file

@ -0,0 +1,508 @@
/* 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;
}

303
src/codec/pemdec.t0 Normal file
View file

@ -0,0 +1,303 @@
\ 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 ;

102
src/config.h Normal file
View file

@ -0,0 +1,102 @@
/*
* 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

791
src/ec/ec_prime_i31.c Normal file
View file

@ -0,0 +1,791 @@
/*
* 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
};

View file

@ -0,0 +1,46 @@
/*
* 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
};

View file

@ -0,0 +1,48 @@
/*
* 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
};

View file

@ -0,0 +1,50 @@
/*
* 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
};

51
src/ec/ec_secp256r1.c Normal file
View file

@ -0,0 +1,51 @@
/*
* 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
};

57
src/ec/ec_secp384r1.c Normal file
View file

@ -0,0 +1,57 @@
/*
* 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
};

64
src/ec/ec_secp521r1.c Normal file
View file

@ -0,0 +1,64 @@
/*
* 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
};

102
src/ec/ecdsa_atr.c Normal file
View file

@ -0,0 +1,102 @@
/*
* 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;
}

47
src/ec/ecdsa_i31_bits.c Normal file
View file

@ -0,0 +1,47 @@
/*
* 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;
}

View file

@ -0,0 +1,45 @@
/*
* 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;
}

176
src/ec/ecdsa_i31_sign_raw.c Normal file
View file

@ -0,0 +1,176 @@
/*
* 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;
}

View file

@ -0,0 +1,44 @@
/*
* 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);
}

Some files were not shown because too many files have changed in this diff Show more